Win32 version of GDK source files and resource files (cursors and icons).
authorTor Lillqvist <tml@src.gnome.org>
Fri, 5 Mar 1999 19:53:56 +0000 (19:53 +0000)
committerTor Lillqvist <tml@src.gnome.org>
Fri, 5 Mar 1999 19:53:56 +0000 (19:53 +0000)
127 files changed:
gdk/win32/gdk.c [new file with mode: 0644]
gdk/win32/gdk.h [new file with mode: 0644]
gdk/win32/gdkcc.c [new file with mode: 0644]
gdk/win32/gdkcolor-win32.c [new file with mode: 0644]
gdk/win32/gdkcolor.c [new file with mode: 0644]
gdk/win32/gdkcursor-win32.c [new file with mode: 0644]
gdk/win32/gdkcursor.c [new file with mode: 0644]
gdk/win32/gdkdnd-win32.c [new file with mode: 0644]
gdk/win32/gdkdnd.c [new file with mode: 0644]
gdk/win32/gdkdraw.c [new file with mode: 0644]
gdk/win32/gdkdrawable-win32.c [new file with mode: 0644]
gdk/win32/gdkevents-win32.c [new file with mode: 0644]
gdk/win32/gdkevents.c [new file with mode: 0644]
gdk/win32/gdkfont-win32.c [new file with mode: 0644]
gdk/win32/gdkfont.c [new file with mode: 0644]
gdk/win32/gdkgc-win32.c [new file with mode: 0644]
gdk/win32/gdkgc.c [new file with mode: 0644]
gdk/win32/gdkglobals-win32.c [new file with mode: 0644]
gdk/win32/gdkglobals.c [new file with mode: 0644]
gdk/win32/gdkim-win32.c [new file with mode: 0644]
gdk/win32/gdkim.c [new file with mode: 0644]
gdk/win32/gdkimage-win32.c [new file with mode: 0644]
gdk/win32/gdkimage.c [new file with mode: 0644]
gdk/win32/gdkinput-win32.c [new file with mode: 0644]
gdk/win32/gdkinput.c [new file with mode: 0644]
gdk/win32/gdkinput.h [new file with mode: 0644]
gdk/win32/gdkmain-win32.c [new file with mode: 0644]
gdk/win32/gdkpixmap-win32.c [new file with mode: 0644]
gdk/win32/gdkpixmap.c [new file with mode: 0644]
gdk/win32/gdkprivate-win32.h [new file with mode: 0644]
gdk/win32/gdkprivate.h [new file with mode: 0644]
gdk/win32/gdkproperty-win32.c [new file with mode: 0644]
gdk/win32/gdkproperty.c [new file with mode: 0644]
gdk/win32/gdkrectangle.c [new file with mode: 0644]
gdk/win32/gdkregion-win32.c [new file with mode: 0644]
gdk/win32/gdkregion.c [new file with mode: 0644]
gdk/win32/gdkrgb.c [new file with mode: 0644]
gdk/win32/gdkselection-win32.c [new file with mode: 0644]
gdk/win32/gdkselection.c [new file with mode: 0644]
gdk/win32/gdktypes.h [new file with mode: 0644]
gdk/win32/gdkvisual-win32.c [new file with mode: 0644]
gdk/win32/gdkvisual.c [new file with mode: 0644]
gdk/win32/gdkwin32.h [new file with mode: 0644]
gdk/win32/gdkwin32id.c [new file with mode: 0644]
gdk/win32/gdkwindow-win32.c [new file with mode: 0644]
gdk/win32/gdkwindow.c [new file with mode: 0644]
gdk/win32/gdkx.h [new file with mode: 0644]
gdk/win32/gdkxid.c [new file with mode: 0644]
gdk/win32/rc/cursor00.cur [new file with mode: 0644]
gdk/win32/rc/cursor02.cur [new file with mode: 0644]
gdk/win32/rc/cursor04.cur [new file with mode: 0644]
gdk/win32/rc/cursor06.cur [new file with mode: 0644]
gdk/win32/rc/cursor08.cur [new file with mode: 0644]
gdk/win32/rc/cursor0a.cur [new file with mode: 0644]
gdk/win32/rc/cursor0c.cur [new file with mode: 0644]
gdk/win32/rc/cursor0e.cur [new file with mode: 0644]
gdk/win32/rc/cursor10.cur [new file with mode: 0644]
gdk/win32/rc/cursor12.cur [new file with mode: 0644]
gdk/win32/rc/cursor14.cur [new file with mode: 0644]
gdk/win32/rc/cursor16.cur [new file with mode: 0644]
gdk/win32/rc/cursor18.cur [new file with mode: 0644]
gdk/win32/rc/cursor1a.cur [new file with mode: 0644]
gdk/win32/rc/cursor1c.cur [new file with mode: 0644]
gdk/win32/rc/cursor1e.cur [new file with mode: 0644]
gdk/win32/rc/cursor20.cur [new file with mode: 0644]
gdk/win32/rc/cursor22.cur [new file with mode: 0644]
gdk/win32/rc/cursor24.cur [new file with mode: 0644]
gdk/win32/rc/cursor26.cur [new file with mode: 0644]
gdk/win32/rc/cursor28.cur [new file with mode: 0644]
gdk/win32/rc/cursor2a.cur [new file with mode: 0644]
gdk/win32/rc/cursor2c.cur [new file with mode: 0644]
gdk/win32/rc/cursor2e.cur [new file with mode: 0644]
gdk/win32/rc/cursor30.cur [new file with mode: 0644]
gdk/win32/rc/cursor32.cur [new file with mode: 0644]
gdk/win32/rc/cursor34.cur [new file with mode: 0644]
gdk/win32/rc/cursor36.cur [new file with mode: 0644]
gdk/win32/rc/cursor38.cur [new file with mode: 0644]
gdk/win32/rc/cursor3a.cur [new file with mode: 0644]
gdk/win32/rc/cursor3c.cur [new file with mode: 0644]
gdk/win32/rc/cursor3e.cur [new file with mode: 0644]
gdk/win32/rc/cursor40.cur [new file with mode: 0644]
gdk/win32/rc/cursor42.cur [new file with mode: 0644]
gdk/win32/rc/cursor44.cur [new file with mode: 0644]
gdk/win32/rc/cursor46.cur [new file with mode: 0644]
gdk/win32/rc/cursor48.cur [new file with mode: 0644]
gdk/win32/rc/cursor4a.cur [new file with mode: 0644]
gdk/win32/rc/cursor4c.cur [new file with mode: 0644]
gdk/win32/rc/cursor4e.cur [new file with mode: 0644]
gdk/win32/rc/cursor50.cur [new file with mode: 0644]
gdk/win32/rc/cursor52.cur [new file with mode: 0644]
gdk/win32/rc/cursor54.cur [new file with mode: 0644]
gdk/win32/rc/cursor56.cur [new file with mode: 0644]
gdk/win32/rc/cursor58.cur [new file with mode: 0644]
gdk/win32/rc/cursor5a.cur [new file with mode: 0644]
gdk/win32/rc/cursor5c.cur [new file with mode: 0644]
gdk/win32/rc/cursor5e.cur [new file with mode: 0644]
gdk/win32/rc/cursor60.cur [new file with mode: 0644]
gdk/win32/rc/cursor62.cur [new file with mode: 0644]
gdk/win32/rc/cursor64.cur [new file with mode: 0644]
gdk/win32/rc/cursor66.cur [new file with mode: 0644]
gdk/win32/rc/cursor68.cur [new file with mode: 0644]
gdk/win32/rc/cursor6a.cur [new file with mode: 0644]
gdk/win32/rc/cursor6c.cur [new file with mode: 0644]
gdk/win32/rc/cursor6e.cur [new file with mode: 0644]
gdk/win32/rc/cursor70.cur [new file with mode: 0644]
gdk/win32/rc/cursor72.cur [new file with mode: 0644]
gdk/win32/rc/cursor74.cur [new file with mode: 0644]
gdk/win32/rc/cursor76.cur [new file with mode: 0644]
gdk/win32/rc/cursor78.cur [new file with mode: 0644]
gdk/win32/rc/cursor7a.cur [new file with mode: 0644]
gdk/win32/rc/cursor7c.cur [new file with mode: 0644]
gdk/win32/rc/cursor7e.cur [new file with mode: 0644]
gdk/win32/rc/cursor80.cur [new file with mode: 0644]
gdk/win32/rc/cursor82.cur [new file with mode: 0644]
gdk/win32/rc/cursor84.cur [new file with mode: 0644]
gdk/win32/rc/cursor86.cur [new file with mode: 0644]
gdk/win32/rc/cursor88.cur [new file with mode: 0644]
gdk/win32/rc/cursor8a.cur [new file with mode: 0644]
gdk/win32/rc/cursor8c.cur [new file with mode: 0644]
gdk/win32/rc/cursor8e.cur [new file with mode: 0644]
gdk/win32/rc/cursor90.cur [new file with mode: 0644]
gdk/win32/rc/cursor92.cur [new file with mode: 0644]
gdk/win32/rc/cursor94.cur [new file with mode: 0644]
gdk/win32/rc/cursor96.cur [new file with mode: 0644]
gdk/win32/rc/cursor98.cur [new file with mode: 0644]
gdk/win32/rc/gdk.rc [new file with mode: 0644]
gdk/win32/rc/gtk.ico [new file with mode: 0644]

diff --git a/gdk/win32/gdk.c b/gdk/win32/gdk.c
new file mode 100644 (file)
index 0000000..0586516
--- /dev/null
@@ -0,0 +1,2237 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-1999 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <io.h>
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkinput.h"
+#include "gdkx.h"
+#include "gdkkeysyms.h"
+#include "gdki18n.h"
+
+static void     gdkx_XConvertCase      (KeySym        symbol,
+                                        KeySym       *lower,
+                                        KeySym       *upper);
+#define XConvertCase gdkx_XConvertCase
+
+static void        gdk_exit_func                (void);
+
+static RETSIGTYPE   gdk_signal                  (int          signum);
+
+
+/* Private variable declarations
+ */
+static int gdk_initialized = 0;        /* 1 if the library is initialized,
+                                * 0 otherwise.
+                                */
+static guint start;            /* We use the millisecond
+                                * timestamps from GetTickCount
+                                */
+static gboolean timerp = TRUE; /* If TRUE use timeouts when waiting
+                                * for Windows messages
+                                */
+static guint32 timer_val = 20; /* Timeout in milliseconds.
+                                */
+
+#ifdef G_ENABLE_DEBUG
+static const GDebugKey gdk_debug_keys[] = {
+  {"events",       GDK_DEBUG_EVENTS},
+  {"misc",         GDK_DEBUG_MISC},
+  {"dnd",          GDK_DEBUG_DND},
+  {"color-context", GDK_DEBUG_COLOR_CONTEXT},
+  {"xim",          GDK_DEBUG_XIM},
+  {"selection",            GDK_DEBUG_SELECTION}
+};
+
+static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);
+
+#endif /* G_ENABLE_DEBUG */
+
+int __stdcall
+DllMain(HINSTANCE hinstDLL,
+       DWORD dwReason,
+       LPVOID reserved)
+{
+  gdk_DLLInstance = hinstDLL;
+
+  return TRUE;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_init
+ *
+ *   Initialize the library for use.
+ *
+ * Arguments:
+ *   "argc" is the number of arguments.
+ *   "argv" is an array of strings.
+ *
+ * Results:
+ *   "argc" and "argv" are modified to reflect any arguments
+ *   which were not handled. (Such arguments should either
+ *   be handled by the application or dismissed).
+ *
+ * Side effects:
+ *   The library is initialized.
+ *
+ *--------------------------------------------------------------
+ */
+
+gboolean
+gdk_init_check (int    *argc,
+               char ***argv)
+{
+  HRESULT hres;
+  gint i, j, k;
+  
+  if (gdk_initialized)
+    return TRUE;
+  
+  if (g_thread_supported ())
+    gdk_threads_mutex = g_mutex_new ();
+  
+  start = GetTickCount ();
+
+#ifdef G_ENABLE_DEBUG
+  {
+    gchar *debug_string = getenv("GDK_DEBUG");
+    if (debug_string != NULL)
+      gdk_debug_flags = g_parse_debug_string (debug_string,
+                                             (GDebugKey *) gdk_debug_keys,
+                                             gdk_ndebug_keys);
+  }
+#endif /* G_ENABLE_DEBUG */
+  
+  if (getenv ("GDK_IGNORE_WINTAB") != NULL)
+    gdk_input_ignore_wintab = TRUE;
+
+  if (argc && argv)
+    {
+      if (*argc > 0)
+       {
+         gchar *d;
+         
+         d = strrchr((*argv)[0], G_DIR_SEPARATOR);
+         if (d != NULL)
+           g_set_prgname (d + 1);
+         else
+           g_set_prgname ((*argv)[0]);
+       }
+      
+      for (i = 1; i < *argc;)
+       {
+#ifdef G_ENABLE_DEBUG    
+         if ((strcmp ("--gdk-debug", (*argv)[i]) == 0) ||
+             (strncmp ("--gdk-debug=", (*argv)[i], 12) == 0))
+           {
+             gchar *equal_pos = strchr ((*argv)[i], '=');
+             
+             if (equal_pos != NULL)
+               {
+                 gdk_debug_flags |= g_parse_debug_string (equal_pos+1,
+                                                          (GDebugKey *) gdk_debug_keys,
+                                                          gdk_ndebug_keys);
+               }
+             else if ((i + 1) < *argc && (*argv)[i + 1])
+               {
+                 gdk_debug_flags |= g_parse_debug_string ((*argv)[i+1],
+                                                          (GDebugKey *) gdk_debug_keys,
+                                                          gdk_ndebug_keys);
+                 (*argv)[i] = NULL;
+                 i += 1;
+               }
+             (*argv)[i] = NULL;
+           }
+         else if ((strcmp ("--gdk-no-debug", (*argv)[i]) == 0) ||
+                  (strncmp ("--gdk-no-debug=", (*argv)[i], 15) == 0))
+           {
+             gchar *equal_pos = strchr ((*argv)[i], '=');
+
+             if (equal_pos != NULL)
+               {
+                 gdk_debug_flags &= ~g_parse_debug_string (equal_pos+1,
+                                                           (GDebugKey *) gdk_debug_keys,
+                                                           gdk_ndebug_keys);
+               }
+             else if ((i + 1) < *argc && (*argv)[i + 1])
+               {
+                 gdk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1],
+                                                           (GDebugKey *) gdk_debug_keys,
+                                                           gdk_ndebug_keys);
+                 (*argv)[i] = NULL;
+                 i += 1;
+               }
+             (*argv)[i] = NULL;
+           }
+         else 
+#endif /* G_ENABLE_DEBUG */
+           if (strcmp ("--sync", (*argv)[i]) == 0)
+             {
+               (*argv)[i] = NULL;
+               GdiSetBatchLimit (1);
+             }
+           else if (strcmp ("--name", (*argv)[i]) == 0)
+             {
+               if ((i + 1) < *argc && (*argv)[i + 1])
+                 {
+                   (*argv)[i++] = NULL;
+                   g_set_prgname ((*argv)[i]);
+                   (*argv)[i] = NULL;
+                 }
+             }
+           else if (strcmp ("--gdk-no-wintab", (*argv)[i]) == 0
+                    || strcmp ("--gdk-ignore-wintab", (*argv)[i]) == 0)
+             {
+               (*argv)[i++] = NULL;
+               gdk_input_ignore_wintab = TRUE;
+             }
+         i += 1;
+       }
+      
+      for (i = 1; i < *argc; i++)
+       {
+         for (k = i; k < *argc; k++)
+           if ((*argv)[k] != NULL)
+             break;
+         
+         if (k > i)
+           {
+             k -= i;
+             for (j = i + k; j < *argc; j++)
+               (*argv)[j-k] = (*argv)[j];
+             *argc -= k;
+           }
+       }
+    }
+  else
+    {
+      g_set_prgname ("<unknown>");
+    }
+  
+  gdk_ProgInstance = GetModuleHandle (NULL);
+  gdk_DC = CreateDC ("DISPLAY", NULL, NULL, NULL);
+
+  gdk_selection_request_msg = RegisterWindowMessage ("gdk-selection-request");
+  gdk_selection_notify_msg = RegisterWindowMessage ("gdk-selection-notify");
+  gdk_selection_clear_msg = RegisterWindowMessage ("gdk-selection-clear");
+
+  gdk_selection_property = gdk_atom_intern ("GDK_SELECTION", FALSE);
+  gdk_clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
+  gdk_win32_dropfiles_atom = gdk_atom_intern ("DROPFILES_DND", FALSE);
+  gdk_ole2_dnd_atom = gdk_atom_intern ("OLE2_DND", FALSE);
+
+  gdk_progclass = g_basename (g_get_prgname ());
+  gdk_progclass[0] = toupper (gdk_progclass[0]);
+
+  gdk_root_window = HWND_DESKTOP;
+
+  g_atexit (gdk_exit_func);
+  
+  gdk_events_init ();
+  gdk_visual_init ();
+  gdk_window_init ();
+  gdk_image_init ();
+  gdk_input_init ();
+  gdk_selection_init ();
+  gdk_dnd_init ();
+
+  gdk_initialized = 1;
+
+  return TRUE;
+}
+
+void
+gdk_init (int *argc, char ***argv)
+{
+  if (!gdk_init_check (argc, argv))
+    {
+      g_warning ("cannot initialize GDK");
+      exit(1);
+    }
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_exit
+ *
+ *   Restores the library to an un-itialized state and exits
+ *   the program using the "exit" system call.
+ *
+ * Arguments:
+ *   "errorcode" is the error value to pass to "exit".
+ *
+ * Results:
+ *   Allocated structures are freed and the program exits
+ *   cleanly.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_exit (int errorcode)
+{
+  /* de-initialisation is done by the gdk_exit_func(),
+     no need to do this here (Alex J.) */
+  exit (errorcode);
+}
+
+void
+gdk_set_use_xshm (gint use_xshm)
+{
+  /* Always on */
+}
+
+gint
+gdk_get_use_xshm (void)
+{
+  return TRUE;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_time_get
+ *
+ *   Get the number of milliseconds since the library was
+ *   initialized.
+ *
+ * Arguments:
+ *
+ * Results:
+ *   The time since the library was initialized is returned.
+ *   This time value is accurate to milliseconds even though
+ *   a more accurate time down to the microsecond could be
+ *   returned.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+guint32
+gdk_time_get (void)
+{
+  guint32 milliseconds;
+  guint32 end = GetTickCount ();
+
+  if (end < start)
+    milliseconds = 0xFFFFFFFF - (start - end) + 1;
+  else
+    milliseconds = end - start;
+
+  return milliseconds;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_timer_get
+ *
+ *   Returns the current timer.
+ *
+ * Arguments:
+ *
+ * Results:
+ *   Returns the current timer interval. This interval is
+ *   in units of milliseconds.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+guint32
+gdk_timer_get (void)
+{
+  return timer_val;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_timer_set
+ *
+ *   Sets the timer interval.
+ *
+ * Arguments:
+ *   "milliseconds" is the new value for the timer.
+ *
+ * Results:
+ *
+ * Side effects:
+ *   Calls to "gdk_event_get" will last for a maximum
+ *   of time of "milliseconds". However, a value of 0
+ *   milliseconds will cause "gdk_event_get" to block
+ *   indefinately until an event is received.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_timer_set (guint32 milliseconds)
+{
+  timer_val = milliseconds;
+#ifdef USE_PEEKNAMEDPIPE
+  /* When using PeekNamedPipe, can't have too long timeouts.
+   */
+  if (timer_val > 10)
+    timer_val = 10;
+  else if (timer_val == 0)
+    timer_val = 0;
+#endif
+}
+
+void
+gdk_timer_enable (void)
+{
+  timerp = TRUE;
+}
+
+void
+gdk_timer_disable (void)
+{
+#ifdef USE_PEEKNAMEDPIPE
+  /* Can't disable timeouts when using PeekNamedPipe */
+#else
+  timerp = FALSE;
+#endif
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_screen_width
+ *
+ *   Return the width of the screen.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_screen_width (void)
+{
+  gint return_val;
+  
+  return_val = gdk_root_parent.width;
+
+  return return_val;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_screen_height
+ *
+ *   Return the height of the screen.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_screen_height (void)
+{
+  gint return_val;
+  
+  return_val = gdk_root_parent.height;
+
+  return return_val;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_screen_width_mm
+ *
+ *   Return the width of the screen in millimetres.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_screen_width_mm (void)
+{
+  HDC hdc;
+  gint return_val;
+
+  hdc = GetDC (NULL);
+  return_val = GetDeviceCaps (hdc, HORZSIZE);
+  ReleaseDC (NULL, hdc);
+
+  return return_val;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_screen_height
+ *
+ *   Return the height of the screen in millimetres.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_screen_height_mm (void)
+{
+  HDC hdc;
+  gint return_val;
+
+  hdc = GetDC (NULL);
+  return_val = GetDeviceCaps (hdc, VERTSIZE);
+  ReleaseDC (NULL, hdc);
+  
+  return return_val;
+}
+
+void
+gdk_key_repeat_disable (void)
+{
+  /* XXX */
+}
+
+void
+gdk_key_repeat_restore (void)
+{
+  /* XXX */
+}
+
+
+/*
+ *--------------------------------------------------------------
+ * gdk_flush
+ *
+ *   Flushes the Xlib output buffer and then waits
+ *   until all requests have been received and processed
+ *   by the X server. The only real use for this function
+ *   is in dealing with XShm.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_flush (void)
+{
+  GdiFlush ();
+}
+
+void
+gdk_beep (void)
+{
+  Beep(1000, 50);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_exit_func
+ *
+ *   This is the "atexit" function that makes sure the
+ *   library gets a chance to cleanup.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *   The library is un-initialized and the program exits.
+ *
+ *--------------------------------------------------------------
+ */
+
+static void
+gdk_exit_func (void)
+{
+  static gboolean in_gdk_exit_func = FALSE;
+  
+  GDK_NOTE (MISC, g_print ("gdk_exit_func\n"));
+  /* This is to avoid an infinite loop if a program segfaults in
+     an atexit() handler (and yes, it does happen, especially if a program
+     has trounced over memory too badly for even g_message to work) */
+  if (in_gdk_exit_func == TRUE)
+    return;
+  in_gdk_exit_func = TRUE;
+  
+  if (gdk_initialized)
+    {
+      gdk_image_exit ();
+      gdk_input_exit ();
+      gdk_key_repeat_restore ();
+      gdk_dnd_exit ();
+      gdk_initialized = 0;
+    }
+}
+
+gchar *
+gdk_get_display(void)
+{
+  return "local:";
+}
+
+/*************************************************************
+ * gdk_error_trap_push:
+ *     Push an error trap. X errors will be trapped until
+ *     the corresponding gdk_error_pop(), which will return
+ *     the error code, if any.
+ *   arguments:
+ *     
+ *   results:
+ *************************************************************/
+
+void
+gdk_error_trap_push (void)
+{
+  /* ??? */
+}
+
+/*************************************************************
+ * gdk_error_trap_pop:
+ *     Pop an error trap added with gdk_error_push()
+ *   arguments:
+ *     
+ *   results:
+ *     0, if no error occured, otherwise the error code.
+ *************************************************************/
+
+gint
+gdk_error_trap_pop (void)
+{
+  /* ??? */
+  return 0;
+}
+
+static void
+gdkx_XConvertCase (KeySym symbol,
+                  KeySym *lower,
+                  KeySym *upper)
+{
+  register KeySym sym = symbol;
+  
+  g_return_if_fail (lower != NULL);
+  g_return_if_fail (upper != NULL);
+  
+  *lower = sym;
+  *upper = sym;
+  
+  switch (sym >> 8)
+    {
+#if    defined (GDK_A) && defined (GDK_Ooblique)
+    case 0: /* Latin 1 */
+      if ((sym >= GDK_A) && (sym <= GDK_Z))
+       *lower += (GDK_a - GDK_A);
+      else if ((sym >= GDK_a) && (sym <= GDK_z))
+       *upper -= (GDK_a - GDK_A);
+      else if ((sym >= GDK_Agrave) && (sym <= GDK_Odiaeresis))
+       *lower += (GDK_agrave - GDK_Agrave);
+      else if ((sym >= GDK_agrave) && (sym <= GDK_odiaeresis))
+       *upper -= (GDK_agrave - GDK_Agrave);
+      else if ((sym >= GDK_Ooblique) && (sym <= GDK_Thorn))
+       *lower += (GDK_oslash - GDK_Ooblique);
+      else if ((sym >= GDK_oslash) && (sym <= GDK_thorn))
+       *upper -= (GDK_oslash - GDK_Ooblique);
+      break;
+#endif /* LATIN1 */
+      
+#if    defined (GDK_Aogonek) && defined (GDK_tcedilla)
+    case 1: /* Latin 2 */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (sym == GDK_Aogonek)
+       *lower = GDK_aogonek;
+      else if (sym >= GDK_Lstroke && sym <= GDK_Sacute)
+       *lower += (GDK_lstroke - GDK_Lstroke);
+      else if (sym >= GDK_Scaron && sym <= GDK_Zacute)
+       *lower += (GDK_scaron - GDK_Scaron);
+      else if (sym >= GDK_Zcaron && sym <= GDK_Zabovedot)
+       *lower += (GDK_zcaron - GDK_Zcaron);
+      else if (sym == GDK_aogonek)
+       *upper = GDK_Aogonek;
+      else if (sym >= GDK_lstroke && sym <= GDK_sacute)
+       *upper -= (GDK_lstroke - GDK_Lstroke);
+      else if (sym >= GDK_scaron && sym <= GDK_zacute)
+       *upper -= (GDK_scaron - GDK_Scaron);
+      else if (sym >= GDK_zcaron && sym <= GDK_zabovedot)
+       *upper -= (GDK_zcaron - GDK_Zcaron);
+      else if (sym >= GDK_Racute && sym <= GDK_Tcedilla)
+       *lower += (GDK_racute - GDK_Racute);
+      else if (sym >= GDK_racute && sym <= GDK_tcedilla)
+       *upper -= (GDK_racute - GDK_Racute);
+      break;
+#endif /* LATIN2 */
+      
+#if    defined (GDK_Hstroke) && defined (GDK_Cabovedot)
+    case 2: /* Latin 3 */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (sym >= GDK_Hstroke && sym <= GDK_Hcircumflex)
+       *lower += (GDK_hstroke - GDK_Hstroke);
+      else if (sym >= GDK_Gbreve && sym <= GDK_Jcircumflex)
+       *lower += (GDK_gbreve - GDK_Gbreve);
+      else if (sym >= GDK_hstroke && sym <= GDK_hcircumflex)
+       *upper -= (GDK_hstroke - GDK_Hstroke);
+      else if (sym >= GDK_gbreve && sym <= GDK_jcircumflex)
+       *upper -= (GDK_gbreve - GDK_Gbreve);
+      else if (sym >= GDK_Cabovedot && sym <= GDK_Scircumflex)
+       *lower += (GDK_cabovedot - GDK_Cabovedot);
+      else if (sym >= GDK_cabovedot && sym <= GDK_scircumflex)
+       *upper -= (GDK_cabovedot - GDK_Cabovedot);
+      break;
+#endif /* LATIN3 */
+      
+#if    defined (GDK_Rcedilla) && defined (GDK_Amacron)
+    case 3: /* Latin 4 */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (sym >= GDK_Rcedilla && sym <= GDK_Tslash)
+       *lower += (GDK_rcedilla - GDK_Rcedilla);
+      else if (sym >= GDK_rcedilla && sym <= GDK_tslash)
+       *upper -= (GDK_rcedilla - GDK_Rcedilla);
+      else if (sym == GDK_ENG)
+       *lower = GDK_eng;
+      else if (sym == GDK_eng)
+       *upper = GDK_ENG;
+      else if (sym >= GDK_Amacron && sym <= GDK_Umacron)
+       *lower += (GDK_amacron - GDK_Amacron);
+      else if (sym >= GDK_amacron && sym <= GDK_umacron)
+       *upper -= (GDK_amacron - GDK_Amacron);
+      break;
+#endif /* LATIN4 */
+      
+#if    defined (GDK_Serbian_DJE) && defined (GDK_Cyrillic_yu)
+    case 6: /* Cyrillic */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (sym >= GDK_Serbian_DJE && sym <= GDK_Serbian_DZE)
+       *lower -= (GDK_Serbian_DJE - GDK_Serbian_dje);
+      else if (sym >= GDK_Serbian_dje && sym <= GDK_Serbian_dze)
+       *upper += (GDK_Serbian_DJE - GDK_Serbian_dje);
+      else if (sym >= GDK_Cyrillic_YU && sym <= GDK_Cyrillic_HARDSIGN)
+       *lower -= (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
+      else if (sym >= GDK_Cyrillic_yu && sym <= GDK_Cyrillic_hardsign)
+       *upper += (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
+      break;
+#endif /* CYRILLIC */
+
+#if    defined (GDK_Greek_ALPHAaccent) && defined (GDK_Greek_finalsmallsigma)
+    case 7: /* Greek */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (sym >= GDK_Greek_ALPHAaccent && sym <= GDK_Greek_OMEGAaccent)
+       *lower += (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
+      else if (sym >= GDK_Greek_alphaaccent && sym <= GDK_Greek_omegaaccent &&
+              sym != GDK_Greek_iotaaccentdieresis &&
+              sym != GDK_Greek_upsilonaccentdieresis)
+       *upper -= (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
+      else if (sym >= GDK_Greek_ALPHA && sym <= GDK_Greek_OMEGA)
+       *lower += (GDK_Greek_alpha - GDK_Greek_ALPHA);
+      else if (sym >= GDK_Greek_alpha && sym <= GDK_Greek_omega &&
+              sym != GDK_Greek_finalsmallsigma)
+       *upper -= (GDK_Greek_alpha - GDK_Greek_ALPHA);
+      break;
+#endif /* GREEK */
+    }
+}
+
+static struct gdk_key {
+  guint keyval;
+  const char *name;
+} gdk_keys_by_keyval[] = {
+  { 0x000020, "space" },
+  { 0x000021, "exclam" },
+  { 0x000022, "quotedbl" },
+  { 0x000023, "numbersign" },
+  { 0x000024, "dollar" },
+  { 0x000025, "percent" },
+  { 0x000026, "ampersand" },
+  { 0x000027, "apostrophe" },
+  { 0x000027, "quoteright" },
+  { 0x000028, "parenleft" },
+  { 0x000029, "parenright" },
+  { 0x00002a, "asterisk" },
+  { 0x00002b, "plus" },
+  { 0x00002c, "comma" },
+  { 0x00002d, "minus" },
+  { 0x00002e, "period" },
+  { 0x00002f, "slash" },
+  { 0x000030, "0" },
+  { 0x000031, "1" },
+  { 0x000032, "2" },
+  { 0x000033, "3" },
+  { 0x000034, "4" },
+  { 0x000035, "5" },
+  { 0x000036, "6" },
+  { 0x000037, "7" },
+  { 0x000038, "8" },
+  { 0x000039, "9" },
+  { 0x00003a, "colon" },
+  { 0x00003b, "semicolon" },
+  { 0x00003c, "less" },
+  { 0x00003d, "equal" },
+  { 0x00003e, "greater" },
+  { 0x00003f, "question" },
+  { 0x000040, "at" },
+  { 0x000041, "A" },
+  { 0x000042, "B" },
+  { 0x000043, "C" },
+  { 0x000044, "D" },
+  { 0x000045, "E" },
+  { 0x000046, "F" },
+  { 0x000047, "G" },
+  { 0x000048, "H" },
+  { 0x000049, "I" },
+  { 0x00004a, "J" },
+  { 0x00004b, "K" },
+  { 0x00004c, "L" },
+  { 0x00004d, "M" },
+  { 0x00004e, "N" },
+  { 0x00004f, "O" },
+  { 0x000050, "P" },
+  { 0x000051, "Q" },
+  { 0x000052, "R" },
+  { 0x000053, "S" },
+  { 0x000054, "T" },
+  { 0x000055, "U" },
+  { 0x000056, "V" },
+  { 0x000057, "W" },
+  { 0x000058, "X" },
+  { 0x000059, "Y" },
+  { 0x00005a, "Z" },
+  { 0x00005b, "bracketleft" },
+  { 0x00005c, "backslash" },
+  { 0x00005d, "bracketright" },
+  { 0x00005e, "asciicircum" },
+  { 0x00005f, "underscore" },
+  { 0x000060, "grave" },
+  { 0x000060, "quoteleft" },
+  { 0x000061, "a" },
+  { 0x000062, "b" },
+  { 0x000063, "c" },
+  { 0x000064, "d" },
+  { 0x000065, "e" },
+  { 0x000066, "f" },
+  { 0x000067, "g" },
+  { 0x000068, "h" },
+  { 0x000069, "i" },
+  { 0x00006a, "j" },
+  { 0x00006b, "k" },
+  { 0x00006c, "l" },
+  { 0x00006d, "m" },
+  { 0x00006e, "n" },
+  { 0x00006f, "o" },
+  { 0x000070, "p" },
+  { 0x000071, "q" },
+  { 0x000072, "r" },
+  { 0x000073, "s" },
+  { 0x000074, "t" },
+  { 0x000075, "u" },
+  { 0x000076, "v" },
+  { 0x000077, "w" },
+  { 0x000078, "x" },
+  { 0x000079, "y" },
+  { 0x00007a, "z" },
+  { 0x00007b, "braceleft" },
+  { 0x00007c, "bar" },
+  { 0x00007d, "braceright" },
+  { 0x00007e, "asciitilde" },
+  { 0x0000a0, "nobreakspace" },
+  { 0x0000a1, "exclamdown" },
+  { 0x0000a2, "cent" },
+  { 0x0000a3, "sterling" },
+  { 0x0000a4, "currency" },
+  { 0x0000a5, "yen" },
+  { 0x0000a6, "brokenbar" },
+  { 0x0000a7, "section" },
+  { 0x0000a8, "diaeresis" },
+  { 0x0000a9, "copyright" },
+  { 0x0000aa, "ordfeminine" },
+  { 0x0000ab, "guillemotleft" },
+  { 0x0000ac, "notsign" },
+  { 0x0000ad, "hyphen" },
+  { 0x0000ae, "registered" },
+  { 0x0000af, "macron" },
+  { 0x0000b0, "degree" },
+  { 0x0000b1, "plusminus" },
+  { 0x0000b2, "twosuperior" },
+  { 0x0000b3, "threesuperior" },
+  { 0x0000b4, "acute" },
+  { 0x0000b5, "mu" },
+  { 0x0000b6, "paragraph" },
+  { 0x0000b7, "periodcentered" },
+  { 0x0000b8, "cedilla" },
+  { 0x0000b9, "onesuperior" },
+  { 0x0000ba, "masculine" },
+  { 0x0000bb, "guillemotright" },
+  { 0x0000bc, "onequarter" },
+  { 0x0000bd, "onehalf" },
+  { 0x0000be, "threequarters" },
+  { 0x0000bf, "questiondown" },
+  { 0x0000c0, "Agrave" },
+  { 0x0000c1, "Aacute" },
+  { 0x0000c2, "Acircumflex" },
+  { 0x0000c3, "Atilde" },
+  { 0x0000c4, "Adiaeresis" },
+  { 0x0000c5, "Aring" },
+  { 0x0000c6, "AE" },
+  { 0x0000c7, "Ccedilla" },
+  { 0x0000c8, "Egrave" },
+  { 0x0000c9, "Eacute" },
+  { 0x0000ca, "Ecircumflex" },
+  { 0x0000cb, "Ediaeresis" },
+  { 0x0000cc, "Igrave" },
+  { 0x0000cd, "Iacute" },
+  { 0x0000ce, "Icircumflex" },
+  { 0x0000cf, "Idiaeresis" },
+  { 0x0000d0, "ETH" },
+  { 0x0000d0, "Eth" },
+  { 0x0000d1, "Ntilde" },
+  { 0x0000d2, "Ograve" },
+  { 0x0000d3, "Oacute" },
+  { 0x0000d4, "Ocircumflex" },
+  { 0x0000d5, "Otilde" },
+  { 0x0000d6, "Odiaeresis" },
+  { 0x0000d7, "multiply" },
+  { 0x0000d8, "Ooblique" },
+  { 0x0000d9, "Ugrave" },
+  { 0x0000da, "Uacute" },
+  { 0x0000db, "Ucircumflex" },
+  { 0x0000dc, "Udiaeresis" },
+  { 0x0000dd, "Yacute" },
+  { 0x0000de, "THORN" },
+  { 0x0000de, "Thorn" },
+  { 0x0000df, "ssharp" },
+  { 0x0000e0, "agrave" },
+  { 0x0000e1, "aacute" },
+  { 0x0000e2, "acircumflex" },
+  { 0x0000e3, "atilde" },
+  { 0x0000e4, "adiaeresis" },
+  { 0x0000e5, "aring" },
+  { 0x0000e6, "ae" },
+  { 0x0000e7, "ccedilla" },
+  { 0x0000e8, "egrave" },
+  { 0x0000e9, "eacute" },
+  { 0x0000ea, "ecircumflex" },
+  { 0x0000eb, "ediaeresis" },
+  { 0x0000ec, "igrave" },
+  { 0x0000ed, "iacute" },
+  { 0x0000ee, "icircumflex" },
+  { 0x0000ef, "idiaeresis" },
+  { 0x0000f0, "eth" },
+  { 0x0000f1, "ntilde" },
+  { 0x0000f2, "ograve" },
+  { 0x0000f3, "oacute" },
+  { 0x0000f4, "ocircumflex" },
+  { 0x0000f5, "otilde" },
+  { 0x0000f6, "odiaeresis" },
+  { 0x0000f7, "division" },
+  { 0x0000f8, "oslash" },
+  { 0x0000f9, "ugrave" },
+  { 0x0000fa, "uacute" },
+  { 0x0000fb, "ucircumflex" },
+  { 0x0000fc, "udiaeresis" },
+  { 0x0000fd, "yacute" },
+  { 0x0000fe, "thorn" },
+  { 0x0000ff, "ydiaeresis" },
+  { 0x0001a1, "Aogonek" },
+  { 0x0001a2, "breve" },
+  { 0x0001a3, "Lstroke" },
+  { 0x0001a5, "Lcaron" },
+  { 0x0001a6, "Sacute" },
+  { 0x0001a9, "Scaron" },
+  { 0x0001aa, "Scedilla" },
+  { 0x0001ab, "Tcaron" },
+  { 0x0001ac, "Zacute" },
+  { 0x0001ae, "Zcaron" },
+  { 0x0001af, "Zabovedot" },
+  { 0x0001b1, "aogonek" },
+  { 0x0001b2, "ogonek" },
+  { 0x0001b3, "lstroke" },
+  { 0x0001b5, "lcaron" },
+  { 0x0001b6, "sacute" },
+  { 0x0001b7, "caron" },
+  { 0x0001b9, "scaron" },
+  { 0x0001ba, "scedilla" },
+  { 0x0001bb, "tcaron" },
+  { 0x0001bc, "zacute" },
+  { 0x0001bd, "doubleacute" },
+  { 0x0001be, "zcaron" },
+  { 0x0001bf, "zabovedot" },
+  { 0x0001c0, "Racute" },
+  { 0x0001c3, "Abreve" },
+  { 0x0001c5, "Lacute" },
+  { 0x0001c6, "Cacute" },
+  { 0x0001c8, "Ccaron" },
+  { 0x0001ca, "Eogonek" },
+  { 0x0001cc, "Ecaron" },
+  { 0x0001cf, "Dcaron" },
+  { 0x0001d0, "Dstroke" },
+  { 0x0001d1, "Nacute" },
+  { 0x0001d2, "Ncaron" },
+  { 0x0001d5, "Odoubleacute" },
+  { 0x0001d8, "Rcaron" },
+  { 0x0001d9, "Uring" },
+  { 0x0001db, "Udoubleacute" },
+  { 0x0001de, "Tcedilla" },
+  { 0x0001e0, "racute" },
+  { 0x0001e3, "abreve" },
+  { 0x0001e5, "lacute" },
+  { 0x0001e6, "cacute" },
+  { 0x0001e8, "ccaron" },
+  { 0x0001ea, "eogonek" },
+  { 0x0001ec, "ecaron" },
+  { 0x0001ef, "dcaron" },
+  { 0x0001f0, "dstroke" },
+  { 0x0001f1, "nacute" },
+  { 0x0001f2, "ncaron" },
+  { 0x0001f5, "odoubleacute" },
+  { 0x0001f8, "rcaron" },
+  { 0x0001f9, "uring" },
+  { 0x0001fb, "udoubleacute" },
+  { 0x0001fe, "tcedilla" },
+  { 0x0001ff, "abovedot" },
+  { 0x0002a1, "Hstroke" },
+  { 0x0002a6, "Hcircumflex" },
+  { 0x0002a9, "Iabovedot" },
+  { 0x0002ab, "Gbreve" },
+  { 0x0002ac, "Jcircumflex" },
+  { 0x0002b1, "hstroke" },
+  { 0x0002b6, "hcircumflex" },
+  { 0x0002b9, "idotless" },
+  { 0x0002bb, "gbreve" },
+  { 0x0002bc, "jcircumflex" },
+  { 0x0002c5, "Cabovedot" },
+  { 0x0002c6, "Ccircumflex" },
+  { 0x0002d5, "Gabovedot" },
+  { 0x0002d8, "Gcircumflex" },
+  { 0x0002dd, "Ubreve" },
+  { 0x0002de, "Scircumflex" },
+  { 0x0002e5, "cabovedot" },
+  { 0x0002e6, "ccircumflex" },
+  { 0x0002f5, "gabovedot" },
+  { 0x0002f8, "gcircumflex" },
+  { 0x0002fd, "ubreve" },
+  { 0x0002fe, "scircumflex" },
+  { 0x0003a2, "kappa" },
+  { 0x0003a2, "kra" },
+  { 0x0003a3, "Rcedilla" },
+  { 0x0003a5, "Itilde" },
+  { 0x0003a6, "Lcedilla" },
+  { 0x0003aa, "Emacron" },
+  { 0x0003ab, "Gcedilla" },
+  { 0x0003ac, "Tslash" },
+  { 0x0003b3, "rcedilla" },
+  { 0x0003b5, "itilde" },
+  { 0x0003b6, "lcedilla" },
+  { 0x0003ba, "emacron" },
+  { 0x0003bb, "gcedilla" },
+  { 0x0003bc, "tslash" },
+  { 0x0003bd, "ENG" },
+  { 0x0003bf, "eng" },
+  { 0x0003c0, "Amacron" },
+  { 0x0003c7, "Iogonek" },
+  { 0x0003cc, "Eabovedot" },
+  { 0x0003cf, "Imacron" },
+  { 0x0003d1, "Ncedilla" },
+  { 0x0003d2, "Omacron" },
+  { 0x0003d3, "Kcedilla" },
+  { 0x0003d9, "Uogonek" },
+  { 0x0003dd, "Utilde" },
+  { 0x0003de, "Umacron" },
+  { 0x0003e0, "amacron" },
+  { 0x0003e7, "iogonek" },
+  { 0x0003ec, "eabovedot" },
+  { 0x0003ef, "imacron" },
+  { 0x0003f1, "ncedilla" },
+  { 0x0003f2, "omacron" },
+  { 0x0003f3, "kcedilla" },
+  { 0x0003f9, "uogonek" },
+  { 0x0003fd, "utilde" },
+  { 0x0003fe, "umacron" },
+  { 0x00047e, "overline" },
+  { 0x0004a1, "kana_fullstop" },
+  { 0x0004a2, "kana_openingbracket" },
+  { 0x0004a3, "kana_closingbracket" },
+  { 0x0004a4, "kana_comma" },
+  { 0x0004a5, "kana_conjunctive" },
+  { 0x0004a5, "kana_middledot" },
+  { 0x0004a6, "kana_WO" },
+  { 0x0004a7, "kana_a" },
+  { 0x0004a8, "kana_i" },
+  { 0x0004a9, "kana_u" },
+  { 0x0004aa, "kana_e" },
+  { 0x0004ab, "kana_o" },
+  { 0x0004ac, "kana_ya" },
+  { 0x0004ad, "kana_yu" },
+  { 0x0004ae, "kana_yo" },
+  { 0x0004af, "kana_tsu" },
+  { 0x0004af, "kana_tu" },
+  { 0x0004b0, "prolongedsound" },
+  { 0x0004b1, "kana_A" },
+  { 0x0004b2, "kana_I" },
+  { 0x0004b3, "kana_U" },
+  { 0x0004b4, "kana_E" },
+  { 0x0004b5, "kana_O" },
+  { 0x0004b6, "kana_KA" },
+  { 0x0004b7, "kana_KI" },
+  { 0x0004b8, "kana_KU" },
+  { 0x0004b9, "kana_KE" },
+  { 0x0004ba, "kana_KO" },
+  { 0x0004bb, "kana_SA" },
+  { 0x0004bc, "kana_SHI" },
+  { 0x0004bd, "kana_SU" },
+  { 0x0004be, "kana_SE" },
+  { 0x0004bf, "kana_SO" },
+  { 0x0004c0, "kana_TA" },
+  { 0x0004c1, "kana_CHI" },
+  { 0x0004c1, "kana_TI" },
+  { 0x0004c2, "kana_TSU" },
+  { 0x0004c2, "kana_TU" },
+  { 0x0004c3, "kana_TE" },
+  { 0x0004c4, "kana_TO" },
+  { 0x0004c5, "kana_NA" },
+  { 0x0004c6, "kana_NI" },
+  { 0x0004c7, "kana_NU" },
+  { 0x0004c8, "kana_NE" },
+  { 0x0004c9, "kana_NO" },
+  { 0x0004ca, "kana_HA" },
+  { 0x0004cb, "kana_HI" },
+  { 0x0004cc, "kana_FU" },
+  { 0x0004cc, "kana_HU" },
+  { 0x0004cd, "kana_HE" },
+  { 0x0004ce, "kana_HO" },
+  { 0x0004cf, "kana_MA" },
+  { 0x0004d0, "kana_MI" },
+  { 0x0004d1, "kana_MU" },
+  { 0x0004d2, "kana_ME" },
+  { 0x0004d3, "kana_MO" },
+  { 0x0004d4, "kana_YA" },
+  { 0x0004d5, "kana_YU" },
+  { 0x0004d6, "kana_YO" },
+  { 0x0004d7, "kana_RA" },
+  { 0x0004d8, "kana_RI" },
+  { 0x0004d9, "kana_RU" },
+  { 0x0004da, "kana_RE" },
+  { 0x0004db, "kana_RO" },
+  { 0x0004dc, "kana_WA" },
+  { 0x0004dd, "kana_N" },
+  { 0x0004de, "voicedsound" },
+  { 0x0004df, "semivoicedsound" },
+  { 0x0005ac, "Arabic_comma" },
+  { 0x0005bb, "Arabic_semicolon" },
+  { 0x0005bf, "Arabic_question_mark" },
+  { 0x0005c1, "Arabic_hamza" },
+  { 0x0005c2, "Arabic_maddaonalef" },
+  { 0x0005c3, "Arabic_hamzaonalef" },
+  { 0x0005c4, "Arabic_hamzaonwaw" },
+  { 0x0005c5, "Arabic_hamzaunderalef" },
+  { 0x0005c6, "Arabic_hamzaonyeh" },
+  { 0x0005c7, "Arabic_alef" },
+  { 0x0005c8, "Arabic_beh" },
+  { 0x0005c9, "Arabic_tehmarbuta" },
+  { 0x0005ca, "Arabic_teh" },
+  { 0x0005cb, "Arabic_theh" },
+  { 0x0005cc, "Arabic_jeem" },
+  { 0x0005cd, "Arabic_hah" },
+  { 0x0005ce, "Arabic_khah" },
+  { 0x0005cf, "Arabic_dal" },
+  { 0x0005d0, "Arabic_thal" },
+  { 0x0005d1, "Arabic_ra" },
+  { 0x0005d2, "Arabic_zain" },
+  { 0x0005d3, "Arabic_seen" },
+  { 0x0005d4, "Arabic_sheen" },
+  { 0x0005d5, "Arabic_sad" },
+  { 0x0005d6, "Arabic_dad" },
+  { 0x0005d7, "Arabic_tah" },
+  { 0x0005d8, "Arabic_zah" },
+  { 0x0005d9, "Arabic_ain" },
+  { 0x0005da, "Arabic_ghain" },
+  { 0x0005e0, "Arabic_tatweel" },
+  { 0x0005e1, "Arabic_feh" },
+  { 0x0005e2, "Arabic_qaf" },
+  { 0x0005e3, "Arabic_kaf" },
+  { 0x0005e4, "Arabic_lam" },
+  { 0x0005e5, "Arabic_meem" },
+  { 0x0005e6, "Arabic_noon" },
+  { 0x0005e7, "Arabic_ha" },
+  { 0x0005e7, "Arabic_heh" },
+  { 0x0005e8, "Arabic_waw" },
+  { 0x0005e9, "Arabic_alefmaksura" },
+  { 0x0005ea, "Arabic_yeh" },
+  { 0x0005eb, "Arabic_fathatan" },
+  { 0x0005ec, "Arabic_dammatan" },
+  { 0x0005ed, "Arabic_kasratan" },
+  { 0x0005ee, "Arabic_fatha" },
+  { 0x0005ef, "Arabic_damma" },
+  { 0x0005f0, "Arabic_kasra" },
+  { 0x0005f1, "Arabic_shadda" },
+  { 0x0005f2, "Arabic_sukun" },
+  { 0x0006a1, "Serbian_dje" },
+  { 0x0006a2, "Macedonia_gje" },
+  { 0x0006a3, "Cyrillic_io" },
+  { 0x0006a4, "Ukrainian_ie" },
+  { 0x0006a4, "Ukranian_je" },
+  { 0x0006a5, "Macedonia_dse" },
+  { 0x0006a6, "Ukrainian_i" },
+  { 0x0006a6, "Ukranian_i" },
+  { 0x0006a7, "Ukrainian_yi" },
+  { 0x0006a7, "Ukranian_yi" },
+  { 0x0006a8, "Cyrillic_je" },
+  { 0x0006a8, "Serbian_je" },
+  { 0x0006a9, "Cyrillic_lje" },
+  { 0x0006a9, "Serbian_lje" },
+  { 0x0006aa, "Cyrillic_nje" },
+  { 0x0006aa, "Serbian_nje" },
+  { 0x0006ab, "Serbian_tshe" },
+  { 0x0006ac, "Macedonia_kje" },
+  { 0x0006ae, "Byelorussian_shortu" },
+  { 0x0006af, "Cyrillic_dzhe" },
+  { 0x0006af, "Serbian_dze" },
+  { 0x0006b0, "numerosign" },
+  { 0x0006b1, "Serbian_DJE" },
+  { 0x0006b2, "Macedonia_GJE" },
+  { 0x0006b3, "Cyrillic_IO" },
+  { 0x0006b4, "Ukrainian_IE" },
+  { 0x0006b4, "Ukranian_JE" },
+  { 0x0006b5, "Macedonia_DSE" },
+  { 0x0006b6, "Ukrainian_I" },
+  { 0x0006b6, "Ukranian_I" },
+  { 0x0006b7, "Ukrainian_YI" },
+  { 0x0006b7, "Ukranian_YI" },
+  { 0x0006b8, "Cyrillic_JE" },
+  { 0x0006b8, "Serbian_JE" },
+  { 0x0006b9, "Cyrillic_LJE" },
+  { 0x0006b9, "Serbian_LJE" },
+  { 0x0006ba, "Cyrillic_NJE" },
+  { 0x0006ba, "Serbian_NJE" },
+  { 0x0006bb, "Serbian_TSHE" },
+  { 0x0006bc, "Macedonia_KJE" },
+  { 0x0006be, "Byelorussian_SHORTU" },
+  { 0x0006bf, "Cyrillic_DZHE" },
+  { 0x0006bf, "Serbian_DZE" },
+  { 0x0006c0, "Cyrillic_yu" },
+  { 0x0006c1, "Cyrillic_a" },
+  { 0x0006c2, "Cyrillic_be" },
+  { 0x0006c3, "Cyrillic_tse" },
+  { 0x0006c4, "Cyrillic_de" },
+  { 0x0006c5, "Cyrillic_ie" },
+  { 0x0006c6, "Cyrillic_ef" },
+  { 0x0006c7, "Cyrillic_ghe" },
+  { 0x0006c8, "Cyrillic_ha" },
+  { 0x0006c9, "Cyrillic_i" },
+  { 0x0006ca, "Cyrillic_shorti" },
+  { 0x0006cb, "Cyrillic_ka" },
+  { 0x0006cc, "Cyrillic_el" },
+  { 0x0006cd, "Cyrillic_em" },
+  { 0x0006ce, "Cyrillic_en" },
+  { 0x0006cf, "Cyrillic_o" },
+  { 0x0006d0, "Cyrillic_pe" },
+  { 0x0006d1, "Cyrillic_ya" },
+  { 0x0006d2, "Cyrillic_er" },
+  { 0x0006d3, "Cyrillic_es" },
+  { 0x0006d4, "Cyrillic_te" },
+  { 0x0006d5, "Cyrillic_u" },
+  { 0x0006d6, "Cyrillic_zhe" },
+  { 0x0006d7, "Cyrillic_ve" },
+  { 0x0006d8, "Cyrillic_softsign" },
+  { 0x0006d9, "Cyrillic_yeru" },
+  { 0x0006da, "Cyrillic_ze" },
+  { 0x0006db, "Cyrillic_sha" },
+  { 0x0006dc, "Cyrillic_e" },
+  { 0x0006dd, "Cyrillic_shcha" },
+  { 0x0006de, "Cyrillic_che" },
+  { 0x0006df, "Cyrillic_hardsign" },
+  { 0x0006e0, "Cyrillic_YU" },
+  { 0x0006e1, "Cyrillic_A" },
+  { 0x0006e2, "Cyrillic_BE" },
+  { 0x0006e3, "Cyrillic_TSE" },
+  { 0x0006e4, "Cyrillic_DE" },
+  { 0x0006e5, "Cyrillic_IE" },
+  { 0x0006e6, "Cyrillic_EF" },
+  { 0x0006e7, "Cyrillic_GHE" },
+  { 0x0006e8, "Cyrillic_HA" },
+  { 0x0006e9, "Cyrillic_I" },
+  { 0x0006ea, "Cyrillic_SHORTI" },
+  { 0x0006eb, "Cyrillic_KA" },
+  { 0x0006ec, "Cyrillic_EL" },
+  { 0x0006ed, "Cyrillic_EM" },
+  { 0x0006ee, "Cyrillic_EN" },
+  { 0x0006ef, "Cyrillic_O" },
+  { 0x0006f0, "Cyrillic_PE" },
+  { 0x0006f1, "Cyrillic_YA" },
+  { 0x0006f2, "Cyrillic_ER" },
+  { 0x0006f3, "Cyrillic_ES" },
+  { 0x0006f4, "Cyrillic_TE" },
+  { 0x0006f5, "Cyrillic_U" },
+  { 0x0006f6, "Cyrillic_ZHE" },
+  { 0x0006f7, "Cyrillic_VE" },
+  { 0x0006f8, "Cyrillic_SOFTSIGN" },
+  { 0x0006f9, "Cyrillic_YERU" },
+  { 0x0006fa, "Cyrillic_ZE" },
+  { 0x0006fb, "Cyrillic_SHA" },
+  { 0x0006fc, "Cyrillic_E" },
+  { 0x0006fd, "Cyrillic_SHCHA" },
+  { 0x0006fe, "Cyrillic_CHE" },
+  { 0x0006ff, "Cyrillic_HARDSIGN" },
+  { 0x0007a1, "Greek_ALPHAaccent" },
+  { 0x0007a2, "Greek_EPSILONaccent" },
+  { 0x0007a3, "Greek_ETAaccent" },
+  { 0x0007a4, "Greek_IOTAaccent" },
+  { 0x0007a5, "Greek_IOTAdiaeresis" },
+  { 0x0007a7, "Greek_OMICRONaccent" },
+  { 0x0007a8, "Greek_UPSILONaccent" },
+  { 0x0007a9, "Greek_UPSILONdieresis" },
+  { 0x0007ab, "Greek_OMEGAaccent" },
+  { 0x0007ae, "Greek_accentdieresis" },
+  { 0x0007af, "Greek_horizbar" },
+  { 0x0007b1, "Greek_alphaaccent" },
+  { 0x0007b2, "Greek_epsilonaccent" },
+  { 0x0007b3, "Greek_etaaccent" },
+  { 0x0007b4, "Greek_iotaaccent" },
+  { 0x0007b5, "Greek_iotadieresis" },
+  { 0x0007b6, "Greek_iotaaccentdieresis" },
+  { 0x0007b7, "Greek_omicronaccent" },
+  { 0x0007b8, "Greek_upsilonaccent" },
+  { 0x0007b9, "Greek_upsilondieresis" },
+  { 0x0007ba, "Greek_upsilonaccentdieresis" },
+  { 0x0007bb, "Greek_omegaaccent" },
+  { 0x0007c1, "Greek_ALPHA" },
+  { 0x0007c2, "Greek_BETA" },
+  { 0x0007c3, "Greek_GAMMA" },
+  { 0x0007c4, "Greek_DELTA" },
+  { 0x0007c5, "Greek_EPSILON" },
+  { 0x0007c6, "Greek_ZETA" },
+  { 0x0007c7, "Greek_ETA" },
+  { 0x0007c8, "Greek_THETA" },
+  { 0x0007c9, "Greek_IOTA" },
+  { 0x0007ca, "Greek_KAPPA" },
+  { 0x0007cb, "Greek_LAMBDA" },
+  { 0x0007cb, "Greek_LAMDA" },
+  { 0x0007cc, "Greek_MU" },
+  { 0x0007cd, "Greek_NU" },
+  { 0x0007ce, "Greek_XI" },
+  { 0x0007cf, "Greek_OMICRON" },
+  { 0x0007d0, "Greek_PI" },
+  { 0x0007d1, "Greek_RHO" },
+  { 0x0007d2, "Greek_SIGMA" },
+  { 0x0007d4, "Greek_TAU" },
+  { 0x0007d5, "Greek_UPSILON" },
+  { 0x0007d6, "Greek_PHI" },
+  { 0x0007d7, "Greek_CHI" },
+  { 0x0007d8, "Greek_PSI" },
+  { 0x0007d9, "Greek_OMEGA" },
+  { 0x0007e1, "Greek_alpha" },
+  { 0x0007e2, "Greek_beta" },
+  { 0x0007e3, "Greek_gamma" },
+  { 0x0007e4, "Greek_delta" },
+  { 0x0007e5, "Greek_epsilon" },
+  { 0x0007e6, "Greek_zeta" },
+  { 0x0007e7, "Greek_eta" },
+  { 0x0007e8, "Greek_theta" },
+  { 0x0007e9, "Greek_iota" },
+  { 0x0007ea, "Greek_kappa" },
+  { 0x0007eb, "Greek_lambda" },
+  { 0x0007eb, "Greek_lamda" },
+  { 0x0007ec, "Greek_mu" },
+  { 0x0007ed, "Greek_nu" },
+  { 0x0007ee, "Greek_xi" },
+  { 0x0007ef, "Greek_omicron" },
+  { 0x0007f0, "Greek_pi" },
+  { 0x0007f1, "Greek_rho" },
+  { 0x0007f2, "Greek_sigma" },
+  { 0x0007f3, "Greek_finalsmallsigma" },
+  { 0x0007f4, "Greek_tau" },
+  { 0x0007f5, "Greek_upsilon" },
+  { 0x0007f6, "Greek_phi" },
+  { 0x0007f7, "Greek_chi" },
+  { 0x0007f8, "Greek_psi" },
+  { 0x0007f9, "Greek_omega" },
+  { 0x0008a1, "leftradical" },
+  { 0x0008a2, "topleftradical" },
+  { 0x0008a3, "horizconnector" },
+  { 0x0008a4, "topintegral" },
+  { 0x0008a5, "botintegral" },
+  { 0x0008a6, "vertconnector" },
+  { 0x0008a7, "topleftsqbracket" },
+  { 0x0008a8, "botleftsqbracket" },
+  { 0x0008a9, "toprightsqbracket" },
+  { 0x0008aa, "botrightsqbracket" },
+  { 0x0008ab, "topleftparens" },
+  { 0x0008ac, "botleftparens" },
+  { 0x0008ad, "toprightparens" },
+  { 0x0008ae, "botrightparens" },
+  { 0x0008af, "leftmiddlecurlybrace" },
+  { 0x0008b0, "rightmiddlecurlybrace" },
+  { 0x0008b1, "topleftsummation" },
+  { 0x0008b2, "botleftsummation" },
+  { 0x0008b3, "topvertsummationconnector" },
+  { 0x0008b4, "botvertsummationconnector" },
+  { 0x0008b5, "toprightsummation" },
+  { 0x0008b6, "botrightsummation" },
+  { 0x0008b7, "rightmiddlesummation" },
+  { 0x0008bc, "lessthanequal" },
+  { 0x0008bd, "notequal" },
+  { 0x0008be, "greaterthanequal" },
+  { 0x0008bf, "integral" },
+  { 0x0008c0, "therefore" },
+  { 0x0008c1, "variation" },
+  { 0x0008c2, "infinity" },
+  { 0x0008c5, "nabla" },
+  { 0x0008c8, "approximate" },
+  { 0x0008c9, "similarequal" },
+  { 0x0008cd, "ifonlyif" },
+  { 0x0008ce, "implies" },
+  { 0x0008cf, "identical" },
+  { 0x0008d6, "radical" },
+  { 0x0008da, "includedin" },
+  { 0x0008db, "includes" },
+  { 0x0008dc, "intersection" },
+  { 0x0008dd, "union" },
+  { 0x0008de, "logicaland" },
+  { 0x0008df, "logicalor" },
+  { 0x0008ef, "partialderivative" },
+  { 0x0008f6, "function" },
+  { 0x0008fb, "leftarrow" },
+  { 0x0008fc, "uparrow" },
+  { 0x0008fd, "rightarrow" },
+  { 0x0008fe, "downarrow" },
+  { 0x0009df, "blank" },
+  { 0x0009e0, "soliddiamond" },
+  { 0x0009e1, "checkerboard" },
+  { 0x0009e2, "ht" },
+  { 0x0009e3, "ff" },
+  { 0x0009e4, "cr" },
+  { 0x0009e5, "lf" },
+  { 0x0009e8, "nl" },
+  { 0x0009e9, "vt" },
+  { 0x0009ea, "lowrightcorner" },
+  { 0x0009eb, "uprightcorner" },
+  { 0x0009ec, "upleftcorner" },
+  { 0x0009ed, "lowleftcorner" },
+  { 0x0009ee, "crossinglines" },
+  { 0x0009ef, "horizlinescan1" },
+  { 0x0009f0, "horizlinescan3" },
+  { 0x0009f1, "horizlinescan5" },
+  { 0x0009f2, "horizlinescan7" },
+  { 0x0009f3, "horizlinescan9" },
+  { 0x0009f4, "leftt" },
+  { 0x0009f5, "rightt" },
+  { 0x0009f6, "bott" },
+  { 0x0009f7, "topt" },
+  { 0x0009f8, "vertbar" },
+  { 0x000aa1, "emspace" },
+  { 0x000aa2, "enspace" },
+  { 0x000aa3, "em3space" },
+  { 0x000aa4, "em4space" },
+  { 0x000aa5, "digitspace" },
+  { 0x000aa6, "punctspace" },
+  { 0x000aa7, "thinspace" },
+  { 0x000aa8, "hairspace" },
+  { 0x000aa9, "emdash" },
+  { 0x000aaa, "endash" },
+  { 0x000aac, "signifblank" },
+  { 0x000aae, "ellipsis" },
+  { 0x000aaf, "doubbaselinedot" },
+  { 0x000ab0, "onethird" },
+  { 0x000ab1, "twothirds" },
+  { 0x000ab2, "onefifth" },
+  { 0x000ab3, "twofifths" },
+  { 0x000ab4, "threefifths" },
+  { 0x000ab5, "fourfifths" },
+  { 0x000ab6, "onesixth" },
+  { 0x000ab7, "fivesixths" },
+  { 0x000ab8, "careof" },
+  { 0x000abb, "figdash" },
+  { 0x000abc, "leftanglebracket" },
+  { 0x000abd, "decimalpoint" },
+  { 0x000abe, "rightanglebracket" },
+  { 0x000abf, "marker" },
+  { 0x000ac3, "oneeighth" },
+  { 0x000ac4, "threeeighths" },
+  { 0x000ac5, "fiveeighths" },
+  { 0x000ac6, "seveneighths" },
+  { 0x000ac9, "trademark" },
+  { 0x000aca, "signaturemark" },
+  { 0x000acb, "trademarkincircle" },
+  { 0x000acc, "leftopentriangle" },
+  { 0x000acd, "rightopentriangle" },
+  { 0x000ace, "emopencircle" },
+  { 0x000acf, "emopenrectangle" },
+  { 0x000ad0, "leftsinglequotemark" },
+  { 0x000ad1, "rightsinglequotemark" },
+  { 0x000ad2, "leftdoublequotemark" },
+  { 0x000ad3, "rightdoublequotemark" },
+  { 0x000ad4, "prescription" },
+  { 0x000ad6, "minutes" },
+  { 0x000ad7, "seconds" },
+  { 0x000ad9, "latincross" },
+  { 0x000ada, "hexagram" },
+  { 0x000adb, "filledrectbullet" },
+  { 0x000adc, "filledlefttribullet" },
+  { 0x000add, "filledrighttribullet" },
+  { 0x000ade, "emfilledcircle" },
+  { 0x000adf, "emfilledrect" },
+  { 0x000ae0, "enopencircbullet" },
+  { 0x000ae1, "enopensquarebullet" },
+  { 0x000ae2, "openrectbullet" },
+  { 0x000ae3, "opentribulletup" },
+  { 0x000ae4, "opentribulletdown" },
+  { 0x000ae5, "openstar" },
+  { 0x000ae6, "enfilledcircbullet" },
+  { 0x000ae7, "enfilledsqbullet" },
+  { 0x000ae8, "filledtribulletup" },
+  { 0x000ae9, "filledtribulletdown" },
+  { 0x000aea, "leftpointer" },
+  { 0x000aeb, "rightpointer" },
+  { 0x000aec, "club" },
+  { 0x000aed, "diamond" },
+  { 0x000aee, "heart" },
+  { 0x000af0, "maltesecross" },
+  { 0x000af1, "dagger" },
+  { 0x000af2, "doubledagger" },
+  { 0x000af3, "checkmark" },
+  { 0x000af4, "ballotcross" },
+  { 0x000af5, "musicalsharp" },
+  { 0x000af6, "musicalflat" },
+  { 0x000af7, "malesymbol" },
+  { 0x000af8, "femalesymbol" },
+  { 0x000af9, "telephone" },
+  { 0x000afa, "telephonerecorder" },
+  { 0x000afb, "phonographcopyright" },
+  { 0x000afc, "caret" },
+  { 0x000afd, "singlelowquotemark" },
+  { 0x000afe, "doublelowquotemark" },
+  { 0x000aff, "cursor" },
+  { 0x000ba3, "leftcaret" },
+  { 0x000ba6, "rightcaret" },
+  { 0x000ba8, "downcaret" },
+  { 0x000ba9, "upcaret" },
+  { 0x000bc0, "overbar" },
+  { 0x000bc2, "downtack" },
+  { 0x000bc3, "upshoe" },
+  { 0x000bc4, "downstile" },
+  { 0x000bc6, "underbar" },
+  { 0x000bca, "jot" },
+  { 0x000bcc, "quad" },
+  { 0x000bce, "uptack" },
+  { 0x000bcf, "circle" },
+  { 0x000bd3, "upstile" },
+  { 0x000bd6, "downshoe" },
+  { 0x000bd8, "rightshoe" },
+  { 0x000bda, "leftshoe" },
+  { 0x000bdc, "lefttack" },
+  { 0x000bfc, "righttack" },
+  { 0x000cdf, "hebrew_doublelowline" },
+  { 0x000ce0, "hebrew_aleph" },
+  { 0x000ce1, "hebrew_bet" },
+  { 0x000ce1, "hebrew_beth" },
+  { 0x000ce2, "hebrew_gimel" },
+  { 0x000ce2, "hebrew_gimmel" },
+  { 0x000ce3, "hebrew_dalet" },
+  { 0x000ce3, "hebrew_daleth" },
+  { 0x000ce4, "hebrew_he" },
+  { 0x000ce5, "hebrew_waw" },
+  { 0x000ce6, "hebrew_zain" },
+  { 0x000ce6, "hebrew_zayin" },
+  { 0x000ce7, "hebrew_chet" },
+  { 0x000ce7, "hebrew_het" },
+  { 0x000ce8, "hebrew_tet" },
+  { 0x000ce8, "hebrew_teth" },
+  { 0x000ce9, "hebrew_yod" },
+  { 0x000cea, "hebrew_finalkaph" },
+  { 0x000ceb, "hebrew_kaph" },
+  { 0x000cec, "hebrew_lamed" },
+  { 0x000ced, "hebrew_finalmem" },
+  { 0x000cee, "hebrew_mem" },
+  { 0x000cef, "hebrew_finalnun" },
+  { 0x000cf0, "hebrew_nun" },
+  { 0x000cf1, "hebrew_samech" },
+  { 0x000cf1, "hebrew_samekh" },
+  { 0x000cf2, "hebrew_ayin" },
+  { 0x000cf3, "hebrew_finalpe" },
+  { 0x000cf4, "hebrew_pe" },
+  { 0x000cf5, "hebrew_finalzade" },
+  { 0x000cf5, "hebrew_finalzadi" },
+  { 0x000cf6, "hebrew_zade" },
+  { 0x000cf6, "hebrew_zadi" },
+  { 0x000cf7, "hebrew_kuf" },
+  { 0x000cf7, "hebrew_qoph" },
+  { 0x000cf8, "hebrew_resh" },
+  { 0x000cf9, "hebrew_shin" },
+  { 0x000cfa, "hebrew_taf" },
+  { 0x000cfa, "hebrew_taw" },
+  { 0x000da1, "Thai_kokai" },
+  { 0x000da2, "Thai_khokhai" },
+  { 0x000da3, "Thai_khokhuat" },
+  { 0x000da4, "Thai_khokhwai" },
+  { 0x000da5, "Thai_khokhon" },
+  { 0x000da6, "Thai_khorakhang" },
+  { 0x000da7, "Thai_ngongu" },
+  { 0x000da8, "Thai_chochan" },
+  { 0x000da9, "Thai_choching" },
+  { 0x000daa, "Thai_chochang" },
+  { 0x000dab, "Thai_soso" },
+  { 0x000dac, "Thai_chochoe" },
+  { 0x000dad, "Thai_yoying" },
+  { 0x000dae, "Thai_dochada" },
+  { 0x000daf, "Thai_topatak" },
+  { 0x000db0, "Thai_thothan" },
+  { 0x000db1, "Thai_thonangmontho" },
+  { 0x000db2, "Thai_thophuthao" },
+  { 0x000db3, "Thai_nonen" },
+  { 0x000db4, "Thai_dodek" },
+  { 0x000db5, "Thai_totao" },
+  { 0x000db6, "Thai_thothung" },
+  { 0x000db7, "Thai_thothahan" },
+  { 0x000db8, "Thai_thothong" },
+  { 0x000db9, "Thai_nonu" },
+  { 0x000dba, "Thai_bobaimai" },
+  { 0x000dbb, "Thai_popla" },
+  { 0x000dbc, "Thai_phophung" },
+  { 0x000dbd, "Thai_fofa" },
+  { 0x000dbe, "Thai_phophan" },
+  { 0x000dbf, "Thai_fofan" },
+  { 0x000dc0, "Thai_phosamphao" },
+  { 0x000dc1, "Thai_moma" },
+  { 0x000dc2, "Thai_yoyak" },
+  { 0x000dc3, "Thai_rorua" },
+  { 0x000dc4, "Thai_ru" },
+  { 0x000dc5, "Thai_loling" },
+  { 0x000dc6, "Thai_lu" },
+  { 0x000dc7, "Thai_wowaen" },
+  { 0x000dc8, "Thai_sosala" },
+  { 0x000dc9, "Thai_sorusi" },
+  { 0x000dca, "Thai_sosua" },
+  { 0x000dcb, "Thai_hohip" },
+  { 0x000dcc, "Thai_lochula" },
+  { 0x000dcd, "Thai_oang" },
+  { 0x000dce, "Thai_honokhuk" },
+  { 0x000dcf, "Thai_paiyannoi" },
+  { 0x000dd0, "Thai_saraa" },
+  { 0x000dd1, "Thai_maihanakat" },
+  { 0x000dd2, "Thai_saraaa" },
+  { 0x000dd3, "Thai_saraam" },
+  { 0x000dd4, "Thai_sarai" },
+  { 0x000dd5, "Thai_saraii" },
+  { 0x000dd6, "Thai_saraue" },
+  { 0x000dd7, "Thai_sarauee" },
+  { 0x000dd8, "Thai_sarau" },
+  { 0x000dd9, "Thai_sarauu" },
+  { 0x000dda, "Thai_phinthu" },
+  { 0x000dde, "Thai_maihanakat_maitho" },
+  { 0x000ddf, "Thai_baht" },
+  { 0x000de0, "Thai_sarae" },
+  { 0x000de1, "Thai_saraae" },
+  { 0x000de2, "Thai_sarao" },
+  { 0x000de3, "Thai_saraaimaimuan" },
+  { 0x000de4, "Thai_saraaimaimalai" },
+  { 0x000de5, "Thai_lakkhangyao" },
+  { 0x000de6, "Thai_maiyamok" },
+  { 0x000de7, "Thai_maitaikhu" },
+  { 0x000de8, "Thai_maiek" },
+  { 0x000de9, "Thai_maitho" },
+  { 0x000dea, "Thai_maitri" },
+  { 0x000deb, "Thai_maichattawa" },
+  { 0x000dec, "Thai_thanthakhat" },
+  { 0x000ded, "Thai_nikhahit" },
+  { 0x000df0, "Thai_leksun" },
+  { 0x000df1, "Thai_leknung" },
+  { 0x000df2, "Thai_leksong" },
+  { 0x000df3, "Thai_leksam" },
+  { 0x000df4, "Thai_leksi" },
+  { 0x000df5, "Thai_lekha" },
+  { 0x000df6, "Thai_lekhok" },
+  { 0x000df7, "Thai_lekchet" },
+  { 0x000df8, "Thai_lekpaet" },
+  { 0x000df9, "Thai_lekkao" },
+  { 0x000ea1, "Hangul_Kiyeog" },
+  { 0x000ea2, "Hangul_SsangKiyeog" },
+  { 0x000ea3, "Hangul_KiyeogSios" },
+  { 0x000ea4, "Hangul_Nieun" },
+  { 0x000ea5, "Hangul_NieunJieuj" },
+  { 0x000ea6, "Hangul_NieunHieuh" },
+  { 0x000ea7, "Hangul_Dikeud" },
+  { 0x000ea8, "Hangul_SsangDikeud" },
+  { 0x000ea9, "Hangul_Rieul" },
+  { 0x000eaa, "Hangul_RieulKiyeog" },
+  { 0x000eab, "Hangul_RieulMieum" },
+  { 0x000eac, "Hangul_RieulPieub" },
+  { 0x000ead, "Hangul_RieulSios" },
+  { 0x000eae, "Hangul_RieulTieut" },
+  { 0x000eaf, "Hangul_RieulPhieuf" },
+  { 0x000eb0, "Hangul_RieulHieuh" },
+  { 0x000eb1, "Hangul_Mieum" },
+  { 0x000eb2, "Hangul_Pieub" },
+  { 0x000eb3, "Hangul_SsangPieub" },
+  { 0x000eb4, "Hangul_PieubSios" },
+  { 0x000eb5, "Hangul_Sios" },
+  { 0x000eb6, "Hangul_SsangSios" },
+  { 0x000eb7, "Hangul_Ieung" },
+  { 0x000eb8, "Hangul_Jieuj" },
+  { 0x000eb9, "Hangul_SsangJieuj" },
+  { 0x000eba, "Hangul_Cieuc" },
+  { 0x000ebb, "Hangul_Khieuq" },
+  { 0x000ebc, "Hangul_Tieut" },
+  { 0x000ebd, "Hangul_Phieuf" },
+  { 0x000ebe, "Hangul_Hieuh" },
+  { 0x000ebf, "Hangul_A" },
+  { 0x000ec0, "Hangul_AE" },
+  { 0x000ec1, "Hangul_YA" },
+  { 0x000ec2, "Hangul_YAE" },
+  { 0x000ec3, "Hangul_EO" },
+  { 0x000ec4, "Hangul_E" },
+  { 0x000ec5, "Hangul_YEO" },
+  { 0x000ec6, "Hangul_YE" },
+  { 0x000ec7, "Hangul_O" },
+  { 0x000ec8, "Hangul_WA" },
+  { 0x000ec9, "Hangul_WAE" },
+  { 0x000eca, "Hangul_OE" },
+  { 0x000ecb, "Hangul_YO" },
+  { 0x000ecc, "Hangul_U" },
+  { 0x000ecd, "Hangul_WEO" },
+  { 0x000ece, "Hangul_WE" },
+  { 0x000ecf, "Hangul_WI" },
+  { 0x000ed0, "Hangul_YU" },
+  { 0x000ed1, "Hangul_EU" },
+  { 0x000ed2, "Hangul_YI" },
+  { 0x000ed3, "Hangul_I" },
+  { 0x000ed4, "Hangul_J_Kiyeog" },
+  { 0x000ed5, "Hangul_J_SsangKiyeog" },
+  { 0x000ed6, "Hangul_J_KiyeogSios" },
+  { 0x000ed7, "Hangul_J_Nieun" },
+  { 0x000ed8, "Hangul_J_NieunJieuj" },
+  { 0x000ed9, "Hangul_J_NieunHieuh" },
+  { 0x000eda, "Hangul_J_Dikeud" },
+  { 0x000edb, "Hangul_J_Rieul" },
+  { 0x000edc, "Hangul_J_RieulKiyeog" },
+  { 0x000edd, "Hangul_J_RieulMieum" },
+  { 0x000ede, "Hangul_J_RieulPieub" },
+  { 0x000edf, "Hangul_J_RieulSios" },
+  { 0x000ee0, "Hangul_J_RieulTieut" },
+  { 0x000ee1, "Hangul_J_RieulPhieuf" },
+  { 0x000ee2, "Hangul_J_RieulHieuh" },
+  { 0x000ee3, "Hangul_J_Mieum" },
+  { 0x000ee4, "Hangul_J_Pieub" },
+  { 0x000ee5, "Hangul_J_PieubSios" },
+  { 0x000ee6, "Hangul_J_Sios" },
+  { 0x000ee7, "Hangul_J_SsangSios" },
+  { 0x000ee8, "Hangul_J_Ieung" },
+  { 0x000ee9, "Hangul_J_Jieuj" },
+  { 0x000eea, "Hangul_J_Cieuc" },
+  { 0x000eeb, "Hangul_J_Khieuq" },
+  { 0x000eec, "Hangul_J_Tieut" },
+  { 0x000eed, "Hangul_J_Phieuf" },
+  { 0x000eee, "Hangul_J_Hieuh" },
+  { 0x000eef, "Hangul_RieulYeorinHieuh" },
+  { 0x000ef0, "Hangul_SunkyeongeumMieum" },
+  { 0x000ef1, "Hangul_SunkyeongeumPieub" },
+  { 0x000ef2, "Hangul_PanSios" },
+  { 0x000ef3, "Hangul_KkogjiDalrinIeung" },
+  { 0x000ef4, "Hangul_SunkyeongeumPhieuf" },
+  { 0x000ef5, "Hangul_YeorinHieuh" },
+  { 0x000ef6, "Hangul_AraeA" },
+  { 0x000ef7, "Hangul_AraeAE" },
+  { 0x000ef8, "Hangul_J_PanSios" },
+  { 0x000ef9, "Hangul_J_KkogjiDalrinIeung" },
+  { 0x000efa, "Hangul_J_YeorinHieuh" },
+  { 0x000eff, "Korean_Won" },
+  { 0x00FD01, "3270_Duplicate" },
+  { 0x00FD02, "3270_FieldMark" },
+  { 0x00FD03, "3270_Right2" },
+  { 0x00FD04, "3270_Left2" },
+  { 0x00FD05, "3270_BackTab" },
+  { 0x00FD06, "3270_EraseEOF" },
+  { 0x00FD07, "3270_EraseInput" },
+  { 0x00FD08, "3270_Reset" },
+  { 0x00FD09, "3270_Quit" },
+  { 0x00FD0A, "3270_PA1" },
+  { 0x00FD0B, "3270_PA2" },
+  { 0x00FD0C, "3270_PA3" },
+  { 0x00FD0D, "3270_Test" },
+  { 0x00FD0E, "3270_Attn" },
+  { 0x00FD0F, "3270_CursorBlink" },
+  { 0x00FD10, "3270_AltCursor" },
+  { 0x00FD11, "3270_KeyClick" },
+  { 0x00FD12, "3270_Jump" },
+  { 0x00FD13, "3270_Ident" },
+  { 0x00FD14, "3270_Rule" },
+  { 0x00FD15, "3270_Copy" },
+  { 0x00FD16, "3270_Play" },
+  { 0x00FD17, "3270_Setup" },
+  { 0x00FD18, "3270_Record" },
+  { 0x00FD19, "3270_ChangeScreen" },
+  { 0x00FD1A, "3270_DeleteWord" },
+  { 0x00FD1B, "3270_ExSelect" },
+  { 0x00FD1C, "3270_CursorSelect" },
+  { 0x00FD1D, "3270_PrintScreen" },
+  { 0x00FD1E, "3270_Enter" },
+  { 0x00FE01, "ISO_Lock" },
+  { 0x00FE02, "ISO_Level2_Latch" },
+  { 0x00FE03, "ISO_Level3_Shift" },
+  { 0x00FE04, "ISO_Level3_Latch" },
+  { 0x00FE05, "ISO_Level3_Lock" },
+  { 0x00FE06, "ISO_Group_Latch" },
+  { 0x00FE07, "ISO_Group_Lock" },
+  { 0x00FE08, "ISO_Next_Group" },
+  { 0x00FE09, "ISO_Next_Group_Lock" },
+  { 0x00FE0A, "ISO_Prev_Group" },
+  { 0x00FE0B, "ISO_Prev_Group_Lock" },
+  { 0x00FE0C, "ISO_First_Group" },
+  { 0x00FE0D, "ISO_First_Group_Lock" },
+  { 0x00FE0E, "ISO_Last_Group" },
+  { 0x00FE0F, "ISO_Last_Group_Lock" },
+  { 0x00FE20, "ISO_Left_Tab" },
+  { 0x00FE21, "ISO_Move_Line_Up" },
+  { 0x00FE22, "ISO_Move_Line_Down" },
+  { 0x00FE23, "ISO_Partial_Line_Up" },
+  { 0x00FE24, "ISO_Partial_Line_Down" },
+  { 0x00FE25, "ISO_Partial_Space_Left" },
+  { 0x00FE26, "ISO_Partial_Space_Right" },
+  { 0x00FE27, "ISO_Set_Margin_Left" },
+  { 0x00FE28, "ISO_Set_Margin_Right" },
+  { 0x00FE29, "ISO_Release_Margin_Left" },
+  { 0x00FE2A, "ISO_Release_Margin_Right" },
+  { 0x00FE2B, "ISO_Release_Both_Margins" },
+  { 0x00FE2C, "ISO_Fast_Cursor_Left" },
+  { 0x00FE2D, "ISO_Fast_Cursor_Right" },
+  { 0x00FE2E, "ISO_Fast_Cursor_Up" },
+  { 0x00FE2F, "ISO_Fast_Cursor_Down" },
+  { 0x00FE30, "ISO_Continuous_Underline" },
+  { 0x00FE31, "ISO_Discontinuous_Underline" },
+  { 0x00FE32, "ISO_Emphasize" },
+  { 0x00FE33, "ISO_Center_Object" },
+  { 0x00FE34, "ISO_Enter" },
+  { 0x00FE50, "dead_grave" },
+  { 0x00FE51, "dead_acute" },
+  { 0x00FE52, "dead_circumflex" },
+  { 0x00FE53, "dead_tilde" },
+  { 0x00FE54, "dead_macron" },
+  { 0x00FE55, "dead_breve" },
+  { 0x00FE56, "dead_abovedot" },
+  { 0x00FE57, "dead_diaeresis" },
+  { 0x00FE58, "dead_abovering" },
+  { 0x00FE59, "dead_doubleacute" },
+  { 0x00FE5A, "dead_caron" },
+  { 0x00FE5B, "dead_cedilla" },
+  { 0x00FE5C, "dead_ogonek" },
+  { 0x00FE5D, "dead_iota" },
+  { 0x00FE5E, "dead_voiced_sound" },
+  { 0x00FE5F, "dead_semivoiced_sound" },
+  { 0x00FE60, "dead_belowdot" },
+  { 0x00FE70, "AccessX_Enable" },
+  { 0x00FE71, "AccessX_Feedback_Enable" },
+  { 0x00FE72, "RepeatKeys_Enable" },
+  { 0x00FE73, "SlowKeys_Enable" },
+  { 0x00FE74, "BounceKeys_Enable" },
+  { 0x00FE75, "StickyKeys_Enable" },
+  { 0x00FE76, "MouseKeys_Enable" },
+  { 0x00FE77, "MouseKeys_Accel_Enable" },
+  { 0x00FE78, "Overlay1_Enable" },
+  { 0x00FE79, "Overlay2_Enable" },
+  { 0x00FE7A, "AudibleBell_Enable" },
+  { 0x00FED0, "First_Virtual_Screen" },
+  { 0x00FED1, "Prev_Virtual_Screen" },
+  { 0x00FED2, "Next_Virtual_Screen" },
+  { 0x00FED4, "Last_Virtual_Screen" },
+  { 0x00FED5, "Terminate_Server" },
+  { 0x00FEE0, "Pointer_Left" },
+  { 0x00FEE1, "Pointer_Right" },
+  { 0x00FEE2, "Pointer_Up" },
+  { 0x00FEE3, "Pointer_Down" },
+  { 0x00FEE4, "Pointer_UpLeft" },
+  { 0x00FEE5, "Pointer_UpRight" },
+  { 0x00FEE6, "Pointer_DownLeft" },
+  { 0x00FEE7, "Pointer_DownRight" },
+  { 0x00FEE8, "Pointer_Button_Dflt" },
+  { 0x00FEE9, "Pointer_Button1" },
+  { 0x00FEEA, "Pointer_Button2" },
+  { 0x00FEEB, "Pointer_Button3" },
+  { 0x00FEEC, "Pointer_Button4" },
+  { 0x00FEED, "Pointer_Button5" },
+  { 0x00FEEE, "Pointer_DblClick_Dflt" },
+  { 0x00FEEF, "Pointer_DblClick1" },
+  { 0x00FEF0, "Pointer_DblClick2" },
+  { 0x00FEF1, "Pointer_DblClick3" },
+  { 0x00FEF2, "Pointer_DblClick4" },
+  { 0x00FEF3, "Pointer_DblClick5" },
+  { 0x00FEF4, "Pointer_Drag_Dflt" },
+  { 0x00FEF5, "Pointer_Drag1" },
+  { 0x00FEF6, "Pointer_Drag2" },
+  { 0x00FEF7, "Pointer_Drag3" },
+  { 0x00FEF8, "Pointer_Drag4" },
+  { 0x00FEF9, "Pointer_EnableKeys" },
+  { 0x00FEFA, "Pointer_Accelerate" },
+  { 0x00FEFB, "Pointer_DfltBtnNext" },
+  { 0x00FEFC, "Pointer_DfltBtnPrev" },
+  { 0x00FEFD, "Pointer_Drag5" },
+  { 0x00FF08, "BackSpace" },
+  { 0x00FF09, "Tab" },
+  { 0x00FF0A, "Linefeed" },
+  { 0x00FF0B, "Clear" },
+  { 0x00FF0D, "Return" },
+  { 0x00FF13, "Pause" },
+  { 0x00FF14, "Scroll_Lock" },
+  { 0x00FF15, "Sys_Req" },
+  { 0x00FF1B, "Escape" },
+  { 0x00FF20, "Multi_key" },
+  { 0x00FF21, "Kanji" },
+  { 0x00FF22, "Muhenkan" },
+  { 0x00FF23, "Henkan" },
+  { 0x00FF23, "Henkan_Mode" },
+  { 0x00FF24, "Romaji" },
+  { 0x00FF25, "Hiragana" },
+  { 0x00FF26, "Katakana" },
+  { 0x00FF27, "Hiragana_Katakana" },
+  { 0x00FF28, "Zenkaku" },
+  { 0x00FF29, "Hankaku" },
+  { 0x00FF2A, "Zenkaku_Hankaku" },
+  { 0x00FF2B, "Touroku" },
+  { 0x00FF2C, "Massyo" },
+  { 0x00FF2D, "Kana_Lock" },
+  { 0x00FF2E, "Kana_Shift" },
+  { 0x00FF2F, "Eisu_Shift" },
+  { 0x00FF30, "Eisu_toggle" },
+  { 0x00FF3C, "SingleCandidate" },
+  { 0x00FF3D, "MultipleCandidate" },
+  { 0x00FF3D, "Zen_Koho" },
+  { 0x00FF3E, "Mae_Koho" },
+  { 0x00FF3E, "PreviousCandidate" },
+  { 0x00FF50, "Home" },
+  { 0x00FF51, "Left" },
+  { 0x00FF52, "Up" },
+  { 0x00FF53, "Right" },
+  { 0x00FF54, "Down" },
+  { 0x00FF55, "Page_Up" },
+  { 0x00FF55, "Prior" },
+  { 0x00FF56, "Next" },
+  { 0x00FF56, "Page_Down" },
+  { 0x00FF57, "End" },
+  { 0x00FF58, "Begin" },
+  { 0x00FF60, "Select" },
+  { 0x00FF61, "Print" },
+  { 0x00FF62, "Execute" },
+  { 0x00FF63, "Insert" },
+  { 0x00FF65, "Undo" },
+  { 0x00FF66, "Redo" },
+  { 0x00FF67, "Menu" },
+  { 0x00FF68, "Find" },
+  { 0x00FF69, "Cancel" },
+  { 0x00FF6A, "Help" },
+  { 0x00FF6B, "Break" },
+  { 0x00FF7E, "Arabic_switch" },
+  { 0x00FF7E, "Greek_switch" },
+  { 0x00FF7E, "Hangul_switch" },
+  { 0x00FF7E, "Hebrew_switch" },
+  { 0x00FF7E, "ISO_Group_Shift" },
+  { 0x00FF7E, "Mode_switch" },
+  { 0x00FF7E, "kana_switch" },
+  { 0x00FF7E, "script_switch" },
+  { 0x00FF7F, "Num_Lock" },
+  { 0x00FF80, "KP_Space" },
+  { 0x00FF89, "KP_Tab" },
+  { 0x00FF8D, "KP_Enter" },
+  { 0x00FF91, "KP_F1" },
+  { 0x00FF92, "KP_F2" },
+  { 0x00FF93, "KP_F3" },
+  { 0x00FF94, "KP_F4" },
+  { 0x00FF95, "KP_Home" },
+  { 0x00FF96, "KP_Left" },
+  { 0x00FF97, "KP_Up" },
+  { 0x00FF98, "KP_Right" },
+  { 0x00FF99, "KP_Down" },
+  { 0x00FF9A, "KP_Page_Up" },
+  { 0x00FF9A, "KP_Prior" },
+  { 0x00FF9B, "KP_Next" },
+  { 0x00FF9B, "KP_Page_Down" },
+  { 0x00FF9C, "KP_End" },
+  { 0x00FF9D, "KP_Begin" },
+  { 0x00FF9E, "KP_Insert" },
+  { 0x00FF9F, "KP_Delete" },
+  { 0x00FFAA, "KP_Multiply" },
+  { 0x00FFAB, "KP_Add" },
+  { 0x00FFAC, "KP_Separator" },
+  { 0x00FFAD, "KP_Subtract" },
+  { 0x00FFAE, "KP_Decimal" },
+  { 0x00FFAF, "KP_Divide" },
+  { 0x00FFB0, "KP_0" },
+  { 0x00FFB1, "KP_1" },
+  { 0x00FFB2, "KP_2" },
+  { 0x00FFB3, "KP_3" },
+  { 0x00FFB4, "KP_4" },
+  { 0x00FFB5, "KP_5" },
+  { 0x00FFB6, "KP_6" },
+  { 0x00FFB7, "KP_7" },
+  { 0x00FFB8, "KP_8" },
+  { 0x00FFB9, "KP_9" },
+  { 0x00FFBD, "KP_Equal" },
+  { 0x00FFBE, "F1" },
+  { 0x00FFBF, "F2" },
+  { 0x00FFC0, "F3" },
+  { 0x00FFC1, "F4" },
+  { 0x00FFC2, "F5" },
+  { 0x00FFC3, "F6" },
+  { 0x00FFC4, "F7" },
+  { 0x00FFC5, "F8" },
+  { 0x00FFC6, "F9" },
+  { 0x00FFC7, "F10" },
+  { 0x00FFC8, "F11" },
+  { 0x00FFC8, "L1" },
+  { 0x00FFC9, "F12" },
+  { 0x00FFC9, "L2" },
+  { 0x00FFCA, "F13" },
+  { 0x00FFCA, "L3" },
+  { 0x00FFCB, "F14" },
+  { 0x00FFCB, "L4" },
+  { 0x00FFCC, "F15" },
+  { 0x00FFCC, "L5" },
+  { 0x00FFCD, "F16" },
+  { 0x00FFCD, "L6" },
+  { 0x00FFCE, "F17" },
+  { 0x00FFCE, "L7" },
+  { 0x00FFCF, "F18" },
+  { 0x00FFCF, "L8" },
+  { 0x00FFD0, "F19" },
+  { 0x00FFD0, "L9" },
+  { 0x00FFD1, "F20" },
+  { 0x00FFD1, "L10" },
+  { 0x00FFD2, "F21" },
+  { 0x00FFD2, "R1" },
+  { 0x00FFD3, "F22" },
+  { 0x00FFD3, "R2" },
+  { 0x00FFD4, "F23" },
+  { 0x00FFD4, "R3" },
+  { 0x00FFD5, "F24" },
+  { 0x00FFD5, "R4" },
+  { 0x00FFD6, "F25" },
+  { 0x00FFD6, "R5" },
+  { 0x00FFD7, "F26" },
+  { 0x00FFD7, "R6" },
+  { 0x00FFD8, "F27" },
+  { 0x00FFD8, "R7" },
+  { 0x00FFD9, "F28" },
+  { 0x00FFD9, "R8" },
+  { 0x00FFDA, "F29" },
+  { 0x00FFDA, "R9" },
+  { 0x00FFDB, "F30" },
+  { 0x00FFDB, "R10" },
+  { 0x00FFDC, "F31" },
+  { 0x00FFDC, "R11" },
+  { 0x00FFDD, "F32" },
+  { 0x00FFDD, "R12" },
+  { 0x00FFDE, "F33" },
+  { 0x00FFDE, "R13" },
+  { 0x00FFDF, "F34" },
+  { 0x00FFDF, "R14" },
+  { 0x00FFE0, "F35" },
+  { 0x00FFE0, "R15" },
+  { 0x00FFE1, "Shift_L" },
+  { 0x00FFE2, "Shift_R" },
+  { 0x00FFE3, "Control_L" },
+  { 0x00FFE4, "Control_R" },
+  { 0x00FFE5, "Caps_Lock" },
+  { 0x00FFE6, "Shift_Lock" },
+  { 0x00FFE7, "Meta_L" },
+  { 0x00FFE8, "Meta_R" },
+  { 0x00FFE9, "Alt_L" },
+  { 0x00FFEA, "Alt_R" },
+  { 0x00FFEB, "Super_L" },
+  { 0x00FFEC, "Super_R" },
+  { 0x00FFED, "Hyper_L" },
+  { 0x00FFEE, "Hyper_R" },
+  { 0x00FFFF, "Delete" },
+  { 0x00ff31, "Hangul" },
+  { 0x00ff32, "Hangul_Start" },
+  { 0x00ff33, "Hangul_End" },
+  { 0x00ff34, "Hangul_Hanja" },
+  { 0x00ff35, "Hangul_Jamo" },
+  { 0x00ff36, "Hangul_Romaja" },
+  { 0x00ff37, "Hangul_Codeinput" },
+  { 0x00ff38, "Hangul_Jeonja" },
+  { 0x00ff39, "Hangul_Banja" },
+  { 0x00ff3a, "Hangul_PreHanja" },
+  { 0x00ff3b, "Hangul_PostHanja" },
+  { 0x00ff3c, "Hangul_SingleCandidate" },
+  { 0x00ff3d, "Hangul_MultipleCandidate" },
+  { 0x00ff3e, "Hangul_PreviousCandidate" },
+  { 0x00ff3f, "Hangul_Special" },
+  { 0xFFFFFF, "VoidSymbol" },
+};
+
+#define GDK_NUM_KEYS (sizeof (gdk_keys_by_keyval) / sizeof (gdk_keys_by_keyval[0]))
+
+static struct gdk_key *gdk_keys_by_name = NULL;
+
+static int
+gdk_keys_keyval_compare (const void *pkey, const void *pbase)
+{
+  return (*(int *) pkey) - ((struct gdk_key *) pbase)->keyval;
+}
+
+const gchar*
+gdk_keyval_name (guint       keyval)
+{
+  struct gdk_key *found =
+    bsearch (&keyval, gdk_keys_by_keyval,
+            GDK_NUM_KEYS, sizeof (struct gdk_key),
+            gdk_keys_keyval_compare);
+  if (found != NULL)
+    return found->name;
+  else
+    return NULL;
+}
+
+static int 
+gdk_key_compare_by_name (const void *a, const void *b)
+{
+  return strcmp (((const struct gdk_key *) a)->name, ((const struct gdk_key *) b)->name);
+}
+
+static int
+gdk_keys_name_compare (const void *pkey, const void *pbase)
+{
+  return strcmp ((const char *) pkey, ((const struct gdk_key *) pbase)->name);
+}
+
+guint
+gdk_keyval_from_name (const gchar *keyval_name)
+{
+  struct gdk_key *found;
+
+  g_return_val_if_fail (keyval_name != NULL, 0);
+  
+  if (gdk_keys_by_name == NULL)
+    {
+      gdk_keys_by_name = g_new (struct gdk_key, GDK_NUM_KEYS);
+
+      memcpy (gdk_keys_by_name, gdk_keys_by_keyval,
+             GDK_NUM_KEYS * sizeof (struct gdk_key));
+
+      qsort (gdk_keys_by_name, GDK_NUM_KEYS, sizeof (struct gdk_key),
+            gdk_key_compare_by_name);
+    }
+
+  found = bsearch (keyval_name, gdk_keys_by_name,
+                  GDK_NUM_KEYS, sizeof (struct gdk_key),
+                  gdk_keys_name_compare);
+  if (found != NULL)
+    return found->keyval;
+  else
+    return GDK_VoidSymbol;
+}
+
+guint
+gdk_keyval_to_upper (guint       keyval)
+{
+  if (keyval)
+    {
+      KeySym lower_val = 0;
+      KeySym upper_val = 0;
+      
+      XConvertCase (keyval, &lower_val, &upper_val);
+      return upper_val;
+    }
+  return 0;
+}
+
+guint
+gdk_keyval_to_lower (guint       keyval)
+{
+  if (keyval)
+    {
+      KeySym lower_val = 0;
+      KeySym upper_val = 0;
+      
+      XConvertCase (keyval, &lower_val, &upper_val);
+      return lower_val;
+    }
+  return 0;
+}
+
+gboolean
+gdk_keyval_is_upper (guint       keyval)
+{
+  if (keyval)
+    {
+      KeySym lower_val = 0;
+      KeySym upper_val = 0;
+      
+      XConvertCase (keyval, &lower_val, &upper_val);
+      return upper_val == keyval;
+    }
+  return TRUE;
+}
+
+gboolean
+gdk_keyval_is_lower (guint        keyval)
+{
+  if (keyval)
+    {
+      KeySym lower_val = 0;
+      KeySym upper_val = 0;
+      
+      XConvertCase (keyval, &lower_val, &upper_val);
+      return lower_val == keyval;
+    }
+  return TRUE;
+}
+
+
+void
+gdk_threads_enter ()
+{
+  GDK_THREADS_ENTER ();
+}
+
+void
+gdk_threads_leave ()
+{
+  GDK_THREADS_LEAVE ();
+}
diff --git a/gdk/win32/gdk.h b/gdk/win32/gdk.h
new file mode 100644 (file)
index 0000000..86335c1
--- /dev/null
@@ -0,0 +1,1033 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GDK_H__
+#define __GDK_H__
+
+
+#include <gdk/gdktypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* Initialization, exit and events
+ */
+#define          GDK_PRIORITY_EVENTS           (G_PRIORITY_DEFAULT)
+void     gdk_init                      (gint           *argc,
+                                        gchar        ***argv);
+gboolean  gdk_init_check               (gint           *argc,
+                                        gchar        ***argv);
+void     gdk_exit                      (gint            error_code);
+gchar*   gdk_set_locale                (void);
+
+/* Push and pop error handlers for X errors
+ */
+void      gdk_error_trap_push           (void);
+gint      gdk_error_trap_pop            (void);
+
+
+gboolean  gdk_events_pending           (void);
+GdkEvent* gdk_event_get                        (void);
+
+GdkEvent* gdk_event_peek                (void);
+GdkEvent* gdk_event_get_graphics_expose (GdkWindow     *window);
+void      gdk_event_put                        (GdkEvent       *event);
+
+GdkEvent* gdk_event_copy               (GdkEvent       *event);
+void     gdk_event_free                (GdkEvent       *event);
+guint32   gdk_event_get_time           (GdkEvent       *event);
+
+void     gdk_event_handler_set         (GdkEventFunc    func,
+                                        gpointer        data,
+                                        GDestroyNotify  notify);
+
+void     gdk_set_show_events           (gint            show_events);
+void     gdk_set_use_xshm              (gint            use_xshm);
+
+gint     gdk_get_show_events           (void);
+gint     gdk_get_use_xshm              (void);
+gchar*   gdk_get_display               (void);
+
+guint32 gdk_time_get     (void);
+guint32 gdk_timer_get    (void);
+void   gdk_timer_set     (guint32 milliseconds);
+void   gdk_timer_enable  (void);
+void   gdk_timer_disable (void);
+
+gint gdk_input_add_full          (gint              source,
+                          GdkInputCondition condition,
+                          GdkInputFunction  function,
+                          gpointer          data,
+                          GdkDestroyNotify  destroy);
+gint gdk_input_add       (gint              source,
+                          GdkInputCondition condition,
+                          GdkInputFunction  function,
+                          gpointer          data);
+void gdk_input_remove    (gint              tag);
+
+gint gdk_pointer_grab  (GdkWindow *     window,
+                        gint            owner_events,
+                        GdkEventMask    event_mask,
+                        GdkWindow *     confine_to,
+                        GdkCursor *     cursor,
+                        guint32         time);
+void gdk_pointer_ungrab (guint32        time);
+
+gint gdk_keyboard_grab  (GdkWindow *     window,
+                         gint            owner_events,
+                         guint32         time);
+void gdk_keyboard_ungrab (guint32        time);
+
+gint gdk_pointer_is_grabbed (void);
+
+gint gdk_screen_width  (void);
+gint gdk_screen_height (void);
+
+gint gdk_screen_width_mm  (void);
+gint gdk_screen_height_mm (void);
+
+void gdk_flush (void);
+void gdk_beep (void);
+
+void gdk_key_repeat_disable (void);
+void gdk_key_repeat_restore (void);
+
+
+/* Visuals
+ */
+gint         gdk_visual_get_best_depth      (void);
+GdkVisualType gdk_visual_get_best_type      (void);
+GdkVisual*    gdk_visual_get_system         (void);
+GdkVisual*    gdk_visual_get_best           (void);
+GdkVisual*    gdk_visual_get_best_with_depth (gint          depth);
+GdkVisual*    gdk_visual_get_best_with_type  (GdkVisualType  visual_type);
+GdkVisual*    gdk_visual_get_best_with_both  (gint          depth,
+                                             GdkVisualType  visual_type);
+
+/* Actually, these are no-ops... */
+GdkVisual* gdk_visual_ref (GdkVisual *visual);
+void      gdk_visual_unref (GdkVisual *visual);
+
+void gdk_query_depths      (gint           **depths,
+                            gint            *count);
+void gdk_query_visual_types (GdkVisualType  **visual_types,
+                            gint            *count);
+
+GList* gdk_list_visuals (void);
+
+
+/* Windows
+ */
+GdkWindow*    gdk_window_new        (GdkWindow     *parent,
+                                     GdkWindowAttr *attributes,
+                                     gint           attributes_mask);
+
+void         gdk_window_destroy     (GdkWindow     *window);
+GdkWindow*    gdk_window_ref        (GdkWindow     *window);
+void         gdk_window_unref       (GdkWindow     *window);
+
+GdkWindow*    gdk_window_at_pointer  (gint        *win_x,
+                                     gint         *win_y);
+void         gdk_window_show        (GdkWindow    *window);
+void         gdk_window_hide        (GdkWindow    *window);
+void         gdk_window_withdraw    (GdkWindow    *window);
+void         gdk_window_move        (GdkWindow    *window,
+                                     gint          x,
+                                     gint          y);
+void         gdk_window_resize      (GdkWindow    *window,
+                                     gint          width,
+                                     gint          height);
+void         gdk_window_move_resize (GdkWindow    *window,
+                                     gint          x,
+                                     gint          y,
+                                     gint          width,
+                                     gint          height);
+void         gdk_window_reparent    (GdkWindow    *window,
+                                     GdkWindow    *new_parent,
+                                     gint          x,
+                                     gint          y);
+void         gdk_window_clear       (GdkWindow    *window);
+void         gdk_window_clear_area  (GdkWindow    *window,
+                                     gint          x,
+                                     gint          y,
+                                     gint          width,
+                                     gint          height);
+void         gdk_window_clear_area_e(GdkWindow    *window,
+                                     gint          x,
+                                     gint          y,
+                                     gint          width,
+                                     gint          height);
+void         gdk_window_copy_area   (GdkWindow    *window,
+                                     GdkGC        *gc,
+                                     gint          x,
+                                     gint          y,
+                                     GdkWindow    *source_window,
+                                     gint          source_x,
+                                     gint          source_y,
+                                     gint          width,
+                                     gint          height);
+void         gdk_window_raise       (GdkWindow    *window);
+void         gdk_window_lower       (GdkWindow    *window);
+
+void         gdk_window_set_user_data   (GdkWindow       *window,
+                                         gpointer         user_data);
+void         gdk_window_set_override_redirect(GdkWindow  *window,
+                                              gboolean override_redirect);
+
+void         gdk_window_add_filter     (GdkWindow     *window,
+                                        GdkFilterFunc  function,
+                                        gpointer       data);
+void         gdk_window_remove_filter  (GdkWindow     *window,
+                                        GdkFilterFunc  function,
+                                        gpointer       data);
+
+/* 
+ * This allows for making shaped (partially transparent) windows
+ * - cool feature, needed for Drag and Drag for example.
+ *  The shape_mask can be the mask
+ *  from gdk_pixmap_create_from_xpm.   Stefan Wille
+ */
+void gdk_window_shape_combine_mask (GdkWindow      *window,
+                                   GdkBitmap       *shape_mask,
+                                   gint             offset_x,
+                                   gint             offset_y);
+/*
+ * This routine allows you to quickly take the shapes of all the child windows
+ * of a window and use their shapes as the shape mask for this window - useful
+ * for container windows that dont want to look like a big box
+ * 
+ * - Raster
+ */
+void gdk_window_set_child_shapes (GdkWindow *window);
+
+/*
+ * This routine allows you to merge (ie ADD) child shapes to your
+ * own window's shape keeping its current shape and ADDING the child
+ * shapes to it.
+ * 
+ * - Raster
+ */
+void gdk_window_merge_child_shapes (GdkWindow *window);
+
+/*
+ * Check if a window has been shown, and whether all it's
+ * parents up to a toplevel have been shown, respectively.
+ * Note that a window that is_viewable below is not necessarily
+ * viewable in the X sense.
+ */
+gboolean gdk_window_is_visible     (GdkWindow *window);
+gboolean gdk_window_is_viewable    (GdkWindow *window);
+
+/* Set static bit gravity on the parent, and static
+ * window gravity on all children.
+ */
+gboolean gdk_window_set_static_gravities (GdkWindow *window,
+                                         gboolean   use_static);   
+/*
+ * The following function adds a global filter for all client
+ * messages of type message_type
+ */
+void gdk_add_client_message_filter (GdkAtom       message_type,
+                                   GdkFilterFunc func,
+                                   gpointer      data);
+
+/* Drag and Drop */
+
+GdkDragContext * gdk_drag_context_new        (void);
+void             gdk_drag_context_ref        (GdkDragContext *context);
+void             gdk_drag_context_unref      (GdkDragContext *context);
+
+/* Destination side */
+
+void             gdk_drag_status        (GdkDragContext   *context,
+                                        GdkDragAction     action,
+                                        guint32           time);
+void             gdk_drop_reply         (GdkDragContext   *context,
+                                        gboolean          ok,
+                                        guint32           time);
+void             gdk_drop_finish        (GdkDragContext   *context,
+                                        gboolean          success,
+                                        guint32           time);
+GdkAtom          gdk_drag_get_selection (GdkDragContext   *context);
+
+/* Source side */
+
+GdkDragContext * gdk_drag_begin      (GdkWindow      *window,
+                                     GList          *targets);
+guint32         gdk_drag_get_protocol (guint32          xid,
+                                      GdkDragProtocol *protocol);
+void             gdk_drag_find_window (GdkDragContext   *context,
+                                      GdkWindow       *drag_window,
+                                      gint             x_root,
+                                      gint             y_root,
+                                      GdkWindow      **dest_window,
+                                      GdkDragProtocol *protocol);
+gboolean        gdk_drag_motion      (GdkDragContext *context,
+                                     GdkWindow      *dest_window,
+                                     GdkDragProtocol protocol,
+                                     gint            x_root, 
+                                     gint            y_root,
+                                     GdkDragAction   suggested_action,
+                                     GdkDragAction   possible_actions,
+                                     guint32         time);
+void            gdk_drag_drop        (GdkDragContext *context,
+                                     guint32         time);
+void            gdk_drag_abort       (GdkDragContext *context,
+                                     guint32         time);
+
+GdkAtom       gdk_drag_get_selection (GdkDragContext *context);
+
+/* GdkWindow */
+
+void         gdk_window_set_hints       (GdkWindow       *window,
+                                         gint             x,
+                                         gint             y,
+                                         gint             min_width,
+                                         gint             min_height,
+                                         gint             max_width,
+                                         gint             max_height,
+                                         gint             flags);
+void          gdk_window_set_geometry_hints (GdkWindow        *window,
+                                            GdkGeometry      *geometry,
+                                            GdkWindowHints    flags);
+void          gdk_set_sm_client_id         (const gchar *sm_client_id);
+
+
+void         gdk_window_set_title         (GdkWindow     *window,
+                                           const gchar   *title);
+void          gdk_window_set_role          (GdkWindow       *window,
+                                           const gchar     *role);
+void          gdk_window_set_transient_for (GdkWindow       *window, 
+                                           GdkWindow       *leader);
+void         gdk_window_set_background  (GdkWindow       *window,
+                                         GdkColor        *color);
+void         gdk_window_set_back_pixmap (GdkWindow       *window,
+                                         GdkPixmap       *pixmap,
+                                         gint             parent_relative);
+void         gdk_window_set_cursor      (GdkWindow       *window,
+                                         GdkCursor       *cursor);
+void         gdk_window_set_colormap    (GdkWindow       *window,
+                                         GdkColormap     *colormap);
+void         gdk_window_get_user_data   (GdkWindow       *window,
+                                         gpointer        *data);
+void         gdk_window_get_geometry    (GdkWindow       *window,
+                                         gint            *x,
+                                         gint            *y,
+                                         gint            *width,
+                                         gint            *height,
+                                         gint            *depth);
+void         gdk_window_get_position    (GdkWindow       *window,
+                                         gint            *x,
+                                         gint            *y);
+void         gdk_window_get_size        (GdkWindow       *window,
+                                         gint            *width,
+                                         gint            *height);
+GdkVisual*    gdk_window_get_visual     (GdkWindow       *window);
+GdkColormap*  gdk_window_get_colormap   (GdkWindow       *window);
+GdkWindowType gdk_window_get_type       (GdkWindow       *window);
+gint         gdk_window_get_origin      (GdkWindow       *window,
+                                         gint            *x,
+                                         gint            *y);
+gboolean      gdk_window_get_deskrelative_origin (GdkWindow      *window,
+                                         gint            *x,
+                                         gint            *y);
+void         gdk_window_get_root_origin (GdkWindow       *window,
+                                         gint            *x,
+                                         gint            *y);
+GdkWindow*    gdk_window_get_pointer    (GdkWindow       *window,
+                                         gint            *x,
+                                         gint            *y,
+                                         GdkModifierType *mask);
+GdkWindow*    gdk_window_get_parent     (GdkWindow       *window);
+GdkWindow*    gdk_window_get_toplevel   (GdkWindow       *window);
+GList*       gdk_window_get_children    (GdkWindow       *window);
+GdkEventMask  gdk_window_get_events     (GdkWindow       *window);
+void         gdk_window_set_events      (GdkWindow       *window,
+                                         GdkEventMask     event_mask);
+
+void         gdk_window_set_icon        (GdkWindow       *window, 
+                                         GdkWindow       *icon_window,
+                                         GdkPixmap       *pixmap,
+                                         GdkBitmap       *mask);
+void         gdk_window_set_icon_name   (GdkWindow       *window, 
+                                         gchar           *name);
+void         gdk_window_set_group       (GdkWindow       *window, 
+                                         GdkWindow       *leader);
+void         gdk_window_set_decorations (GdkWindow       *window,
+                                         GdkWMDecoration  decorations);
+void         gdk_window_set_functions   (GdkWindow       *window,
+                                         GdkWMFunction    functions);
+GList *       gdk_window_get_toplevels   (void);
+
+void          gdk_window_register_dnd    (GdkWindow       *window);
+
+void          gdk_drawable_set_data      (GdkDrawable     *drawable,
+                                         const gchar     *key,
+                                         gpointer         data,
+                                         GDestroyNotify   destroy_func);
+                                         
+
+/* Cursors
+ */
+GdkCursor* gdk_cursor_new               (GdkCursorType   cursor_type);
+GdkCursor* gdk_cursor_new_from_pixmap   (GdkPixmap       *source,
+                                         GdkPixmap       *mask,
+                                         GdkColor        *fg,
+                                         GdkColor        *bg,
+                                         gint             x,
+                                         gint             y);
+void      gdk_cursor_destroy            (GdkCursor      *cursor);
+
+
+/* GCs
+ */
+GdkGC* gdk_gc_new                (GdkWindow        *window);
+GdkGC* gdk_gc_new_with_values    (GdkWindow        *window,
+                                  GdkGCValues      *values,
+                                  GdkGCValuesMask   values_mask);
+GdkGC* gdk_gc_ref                (GdkGC            *gc);
+void   gdk_gc_unref              (GdkGC            *gc);
+void   gdk_gc_destroy            (GdkGC            *gc);
+void   gdk_gc_get_values         (GdkGC            *gc,
+                                  GdkGCValues      *values);
+void   gdk_gc_set_foreground     (GdkGC            *gc,
+                                  GdkColor         *color);
+void   gdk_gc_set_background     (GdkGC            *gc,
+                                  GdkColor         *color);
+void   gdk_gc_set_font           (GdkGC            *gc,
+                                  GdkFont          *font);
+void   gdk_gc_set_function       (GdkGC            *gc,
+                                  GdkFunction       function);
+void   gdk_gc_set_fill           (GdkGC            *gc,
+                                  GdkFill           fill);
+void   gdk_gc_set_tile           (GdkGC            *gc,
+                                  GdkPixmap        *tile);
+void   gdk_gc_set_stipple        (GdkGC            *gc,
+                                  GdkPixmap        *stipple);
+void   gdk_gc_set_ts_origin      (GdkGC            *gc,
+                                  gint              x,
+                                  gint              y);
+void   gdk_gc_set_clip_origin    (GdkGC            *gc,
+                                  gint              x,
+                                  gint              y);
+void   gdk_gc_set_clip_mask      (GdkGC            *gc,
+                                  GdkBitmap        *mask);
+void   gdk_gc_set_clip_rectangle  (GdkGC           *gc,
+                                  GdkRectangle     *rectangle);
+void   gdk_gc_set_clip_region    (GdkGC            *gc,
+                                  GdkRegion        *region);
+void   gdk_gc_set_subwindow      (GdkGC            *gc,
+                                  GdkSubwindowMode  mode);
+void   gdk_gc_set_exposures      (GdkGC            *gc,
+                                  gint              exposures);
+void   gdk_gc_set_line_attributes (GdkGC           *gc,
+                                  gint              line_width,
+                                  GdkLineStyle      line_style,
+                                  GdkCapStyle       cap_style,
+                                  GdkJoinStyle      join_style);
+void   gdk_gc_set_dashes          (GdkGC            *gc,
+                                  gint              dash_offset,
+                                  gchar             dash_list[],
+                                  gint              n);
+void   gdk_gc_copy               (GdkGC             *dst_gc,
+                                  GdkGC             *src_gc);
+
+
+/* Pixmaps
+ */
+GdkPixmap* gdk_pixmap_new              (GdkWindow  *window,
+                                        gint        width,
+                                        gint        height,
+                                        gint        depth);
+GdkPixmap* gdk_pixmap_create_on_shared_image
+                                       (GdkImage  **image_return,
+                                        GdkWindow  *window,
+                                        GdkVisual  *visual,
+                                        gint        width,
+                                        gint        height,
+                                        gint        depth);
+GdkBitmap* gdk_bitmap_create_from_data (GdkWindow   *window,
+                                        const gchar *data,
+                                        gint         width,
+                                        gint         height);
+GdkPixmap* gdk_pixmap_create_from_data (GdkWindow   *window,
+                                        const gchar *data,
+                                        gint         width,
+                                        gint         height,
+                                        gint         depth,
+                                        GdkColor    *fg,
+                                        GdkColor    *bg);
+GdkPixmap* gdk_pixmap_create_from_xpm  (GdkWindow  *window,
+                                        GdkBitmap **mask,
+                                        GdkColor   *transparent_color,
+                                        const gchar *filename);
+GdkPixmap* gdk_pixmap_colormap_create_from_xpm 
+                                        (GdkWindow   *window,
+                                        GdkColormap *colormap,
+                                        GdkBitmap  **mask,
+                                        GdkColor    *transparent_color,
+                                        const gchar *filename);
+GdkPixmap* gdk_pixmap_create_from_xpm_d (GdkWindow  *window,
+                                        GdkBitmap **mask,
+                                        GdkColor   *transparent_color,
+                                        gchar     **data);
+GdkPixmap* gdk_pixmap_colormap_create_from_xpm_d 
+                                        (GdkWindow   *window,
+                                        GdkColormap *colormap,
+                                        GdkBitmap  **mask,
+                                        GdkColor    *transparent_color,
+                                        gchar     **data);
+GdkPixmap *gdk_pixmap_ref              (GdkPixmap  *pixmap);
+void      gdk_pixmap_unref             (GdkPixmap  *pixmap);
+
+GdkBitmap *gdk_bitmap_ref              (GdkBitmap  *pixmap);
+void      gdk_bitmap_unref             (GdkBitmap  *pixmap);
+
+
+/* Images
+ */
+GdkImage* gdk_image_new_bitmap(GdkVisual     *visual,
+                               gpointer      data,
+                               gint          width,
+                               gint          height);
+GdkImage*  gdk_image_new       (GdkImageType  type,
+                               GdkVisual    *visual,
+                               gint          width,
+                               gint          height);
+GdkImage*  gdk_image_bitmap_new(GdkImageType  type,
+                               GdkVisual    *visual,
+                               gint          width,
+                               gint          height);
+GdkImage*  gdk_image_get       (GdkWindow    *window,
+                               gint          x,
+                               gint          y,
+                               gint          width,
+                               gint          height);
+void      gdk_image_put_pixel (GdkImage     *image,
+                               gint          x,
+                               gint          y,
+                               guint32       pixel);
+guint32           gdk_image_get_pixel (GdkImage     *image,
+                               gint          x,
+                               gint          y);
+void      gdk_image_destroy   (GdkImage     *image);
+
+
+/* Color
+ */
+GdkColormap* gdk_colormap_new    (GdkVisual   *visual,
+                                  gint         allocate);
+GdkColormap* gdk_colormap_ref    (GdkColormap *cmap);
+void        gdk_colormap_unref   (GdkColormap *cmap);
+
+GdkColormap* gdk_colormap_get_system      (void);
+gint        gdk_colormap_get_system_size  (void);
+
+void gdk_colormap_change (GdkColormap  *colormap,
+                         gint           ncolors);
+
+
+gint  gdk_colormap_alloc_colors   (GdkColormap *colormap,
+                                  GdkColor    *colors,
+                                  gint         ncolors,
+                                  gboolean     writeable,
+                                  gboolean     best_match,
+                                  gboolean    *success);
+gboolean gdk_colormap_alloc_color (GdkColormap *colormap,
+                                  GdkColor    *color,
+                                  gboolean     writeable,
+                                  gboolean     best_match);
+void     gdk_colormap_free_colors (GdkColormap *colormap,
+                                  GdkColor    *colors,
+                                  gint         ncolors);
+
+GdkVisual *gdk_colormap_get_visual (GdkColormap *colormap);
+     
+GdkColor *gdk_color_copy (GdkColor *color);
+void      gdk_color_free (GdkColor *color);
+
+gint gdk_color_parse    (const gchar   *spec,
+                         GdkColor      *color);
+guint gdk_color_hash     (const GdkColor *colora);
+gint gdk_color_equal    (const GdkColor *colora,
+                         const GdkColor *colorb);
+
+
+/* The following functions are deprecated */
+void gdk_colors_store   (GdkColormap   *colormap,
+                         GdkColor      *colors,
+                         gint           ncolors);
+gint gdk_colors_alloc   (GdkColormap   *colormap,
+                         gint           contiguous,
+                         gulong        *planes,
+                         gint           nplanes,
+                         gulong        *pixels,
+                         gint           npixels);
+void gdk_colors_free    (GdkColormap   *colormap,
+                         gulong        *pixels,
+                         gint           npixels,
+                         gulong         planes);
+gint gdk_color_white    (GdkColormap   *colormap,
+                         GdkColor      *color);
+gint gdk_color_black    (GdkColormap   *colormap,
+                         GdkColor      *color);
+gint gdk_color_alloc    (GdkColormap   *colormap,
+                         GdkColor      *color);
+gint gdk_color_change   (GdkColormap   *colormap,
+                         GdkColor      *color);
+
+
+/* Fonts
+ */
+GdkFont* gdk_font_load     (const gchar    *font_name);
+GdkFont* gdk_fontset_load   (gchar          *fontset_name);
+GdkFont* gdk_font_ref      (GdkFont        *font);
+void    gdk_font_unref     (GdkFont        *font);
+gint    gdk_font_id        (const GdkFont  *font);
+gint    gdk_font_equal     (const GdkFont  *fonta,
+                            const GdkFont  *fontb);
+gint    gdk_string_width   (GdkFont        *font,
+                            const gchar    *string);
+gint    gdk_text_width     (GdkFont        *font,
+                            const gchar    *text,
+                            gint            text_length);
+gint    gdk_text_width_wc  (GdkFont        *font,
+                            const GdkWChar *text,
+                            gint            text_length);
+gint    gdk_char_width     (GdkFont        *font,
+                            gchar           character);
+gint    gdk_char_width_wc  (GdkFont        *font,
+                            GdkWChar        character);
+gint    gdk_string_measure (GdkFont        *font,
+                            const gchar    *string);
+gint    gdk_text_measure   (GdkFont        *font,
+                            const gchar    *text,
+                            gint            text_length);
+gint    gdk_char_measure   (GdkFont        *font,
+                            gchar           character);
+gint    gdk_string_height  (GdkFont        *font,
+                            const gchar    *string);
+gint    gdk_text_height    (GdkFont        *font,
+                            const gchar    *text,
+                            gint            text_length);
+gint    gdk_char_height    (GdkFont        *font,
+                            gchar           character);
+
+void     gdk_text_extents   (GdkFont     *font,
+                            const gchar *text,
+                            gint         text_length,
+                            gint        *lbearing,
+                            gint        *rbearing,
+                            gint        *width,
+                            gint        *ascent,
+                            gint        *descent);
+void    gdk_text_extents_wc (GdkFont        *font,
+                            const GdkWChar *text,
+                            gint            text_length,
+                            gint           *lbearing,
+                            gint           *rbearing,
+                            gint           *width,
+                            gint           *ascent,
+                            gint           *descent);
+void     gdk_string_extents (GdkFont     *font,
+                            const gchar *string,
+                            gint        *lbearing,
+                            gint        *rbearing,
+                            gint        *width,
+                            gint        *ascent,
+                            gint        *descent);
+
+/* Drawing
+ */
+void gdk_draw_point     (GdkDrawable  *drawable,
+                         GdkGC        *gc,
+                         gint          x,
+                         gint          y);
+void gdk_draw_line      (GdkDrawable  *drawable,
+                         GdkGC        *gc,
+                         gint          x1,
+                         gint          y1,
+                         gint          x2,
+                         gint          y2);
+void gdk_draw_rectangle         (GdkDrawable  *drawable,
+                         GdkGC        *gc,
+                         gint          filled,
+                         gint          x,
+                         gint          y,
+                         gint          width,
+                         gint          height);
+void gdk_draw_arc       (GdkDrawable  *drawable,
+                         GdkGC        *gc,
+                         gint          filled,
+                         gint          x,
+                         gint          y,
+                         gint          width,
+                         gint          height,
+                         gint          angle1,
+                         gint          angle2);
+void gdk_draw_polygon   (GdkDrawable  *drawable,
+                         GdkGC        *gc,
+                         gint          filled,
+                         GdkPoint     *points,
+                         gint          npoints);
+void gdk_draw_string    (GdkDrawable  *drawable,
+                         GdkFont      *font,
+                         GdkGC        *gc,
+                         gint          x,
+                         gint          y,
+                         const gchar  *string);
+void gdk_draw_text      (GdkDrawable  *drawable,
+                         GdkFont      *font,
+                         GdkGC        *gc,
+                         gint          x,
+                         gint          y,
+                         const gchar  *text,
+                         gint          text_length);
+void gdk_draw_text_wc   (GdkDrawable    *drawable,
+                         GdkFont        *font,
+                         GdkGC          *gc,
+                         gint            x,
+                         gint            y,
+                         const GdkWChar *text,
+                         gint            text_length);
+void gdk_draw_pixmap    (GdkDrawable  *drawable,
+                         GdkGC        *gc,
+                         GdkDrawable  *src,
+                         gint          xsrc,
+                         gint          ysrc,
+                         gint          xdest,
+                         gint          ydest,
+                         gint          width,
+                         gint          height);
+void gdk_draw_bitmap    (GdkDrawable  *drawable,
+                         GdkGC        *gc,
+                         GdkDrawable  *src,
+                         gint          xsrc,
+                         gint          ysrc,
+                         gint          xdest,
+                         gint          ydest,
+                         gint          width,
+                         gint          height);
+void gdk_draw_image     (GdkDrawable  *drawable,
+                         GdkGC        *gc,
+                         GdkImage     *image,
+                         gint          xsrc,
+                         gint          ysrc,
+                         gint          xdest,
+                         gint          ydest,
+                         gint          width,
+                         gint          height);
+void gdk_draw_points    (GdkDrawable  *drawable,
+                         GdkGC        *gc,
+                         GdkPoint     *points,
+                         gint          npoints);
+void gdk_draw_segments  (GdkDrawable  *drawable,
+                         GdkGC        *gc,
+                         GdkSegment   *segs,
+                         gint          nsegs);
+void gdk_draw_lines      (GdkDrawable  *drawable,
+                          GdkGC        *gc,
+                          GdkPoint     *points,
+                          gint          npoints);
+
+
+
+/* Selections
+ */
+gint      gdk_selection_owner_set (GdkWindow    *owner,
+                                   GdkAtom       selection,
+                                   guint32       time,
+                                   gint          send_event);
+GdkWindow* gdk_selection_owner_get (GdkAtom      selection);
+void      gdk_selection_convert   (GdkWindow    *requestor,
+                                   GdkAtom       selection,
+                                   GdkAtom       target,
+                                   guint32       time);
+gint      gdk_selection_property_get (GdkWindow  *requestor,
+                                      guchar    **data,
+                                      GdkAtom    *prop_type,
+                                      gint       *prop_format);
+void      gdk_selection_send_notify (guint32       requestor,
+                                     GdkAtom       selection,
+                                     GdkAtom       target,
+                                     GdkAtom       property,
+                                     guint32       time);
+
+gint      gdk_text_property_to_text_list (GdkAtom encoding, gint format,
+                                          guchar *text, gint length,
+                                          gchar ***list);
+void      gdk_free_text_list             (gchar **list);
+gint      gdk_string_to_compound_text    (gchar *str,
+                                          GdkAtom *encoding, gint *format,
+                                          guchar **ctext, gint *length);
+void      gdk_free_compound_text         (guchar *ctext);
+
+/* Properties
+ */
+GdkAtom gdk_atom_intern            (const gchar *atom_name,
+                            gint         only_if_exists);
+gchar* gdk_atom_name       (GdkAtom atom);
+gint   gdk_property_get    (GdkWindow   *window,
+                            GdkAtom      property,
+                            GdkAtom      type,
+                            gulong       offset,
+                            gulong       length,
+                            gint         pdelete,
+                            GdkAtom     *actual_property_type,
+                            gint        *actual_format,
+                            gint        *actual_length,
+                            guchar     **data);
+
+void   gdk_property_change (GdkWindow   *window,
+                            GdkAtom      property,
+                            GdkAtom      type,
+                            gint         format,
+                            GdkPropMode  mode,
+                            guchar      *data,
+                            gint         nelements);
+void   gdk_property_delete (GdkWindow   *window,
+                            GdkAtom      property);
+
+
+/* Rectangle utilities
+ */
+gint gdk_rectangle_intersect (GdkRectangle *src1,
+                             GdkRectangle *src2,
+                             GdkRectangle *dest);
+void gdk_rectangle_union     (GdkRectangle *src1,
+                             GdkRectangle *src2,
+                             GdkRectangle *dest);
+
+/* XInput support
+ */
+
+void gdk_input_init                        (void);
+void gdk_input_exit                        (void);
+GList *gdk_input_list_devices              (void);
+void gdk_input_set_extension_events        (GdkWindow *window,
+                                            gint mask,
+                                            GdkExtensionMode mode);
+void gdk_input_set_source                  (guint32 deviceid,
+                                            GdkInputSource source);
+gint gdk_input_set_mode                            (guint32 deviceid,
+                                            GdkInputMode mode);
+void gdk_input_set_axes                            (guint32 deviceid,
+                                            GdkAxisUse *axes);
+void gdk_input_set_key                     (guint32 deviceid,
+                                            guint   index,
+                                            guint   keyval,
+                                            GdkModifierType modifiers);
+void gdk_input_window_get_pointer     (GdkWindow       *window,
+                                      guint32         deviceid,
+                                      gdouble         *x,
+                                      gdouble         *y,
+                                      gdouble         *pressure,
+                                      gdouble         *xtilt,
+                                      gdouble         *ytilt,
+                                      GdkModifierType *mask);
+
+GdkTimeCoord *gdk_input_motion_events (GdkWindow *window,
+                                      guint32 deviceid,
+                                      guint32 start,
+                                      guint32 stop,
+                                      gint *nevents_return);
+
+/* International Input Method Support Functions
+ */
+
+gint         gdk_im_ready         (void);
+
+void         gdk_im_begin         (GdkIC               *ic, 
+                                   GdkWindow           *window);
+void         gdk_im_end                   (void);
+GdkIMStyle   gdk_im_decide_style   (GdkIMStyle           supported_style);
+GdkIMStyle   gdk_im_set_best_style (GdkIMStyle           best_allowed_style);
+
+GdkIC*       gdk_ic_new                   (GdkICAttr           *attr,
+                                   GdkICAttributesType mask);
+void         gdk_ic_destroy       (GdkIC               *ic);
+GdkIMStyle   gdk_ic_get_style     (GdkIC               *ic);
+GdkEventMask gdk_ic_get_events     (GdkIC               *ic);
+
+GdkICAttr*   gdk_ic_attr_new       (void);
+void         gdk_ic_attr_destroy   (GdkICAttr *attr);
+
+GdkICAttributesType  gdk_ic_set_attr (GdkIC              *ic,  
+                                      GdkICAttr          *attr,
+                                      GdkICAttributesType mask);
+GdkICAttributesType  gdk_ic_get_attr (GdkIC              *ic, 
+                                      GdkICAttr          *attr,
+                                      GdkICAttributesType mask);
+
+/* Conversion functions between wide char and multibyte strings. 
+ */
+gchar     *gdk_wcstombs          (const GdkWChar   *src);
+gint       gdk_mbstowcs          (GdkWChar         *dest,
+                                 const gchar      *src,
+                                 gint              dest_max);
+
+
+/* Color Context */
+
+GdkColorContext *gdk_color_context_new                   (GdkVisual   *visual,
+                                                          GdkColormap *colormap);
+
+GdkColorContext *gdk_color_context_new_mono              (GdkVisual   *visual,
+                                                          GdkColormap *colormap);
+
+void            gdk_color_context_free                   (GdkColorContext *cc);
+
+gulong          gdk_color_context_get_pixel              (GdkColorContext *cc,
+                                                          gushort          red,
+                                                          gushort          green,
+                                                          gushort          blue,
+                                                          gint            *failed);
+void            gdk_color_context_get_pixels             (GdkColorContext *cc,
+                                                          gushort         *reds,
+                                                          gushort         *greens,
+                                                          gushort         *blues,
+                                                          gint             ncolors,
+                                                          gulong          *colors,
+                                                          gint            *nallocated);
+void            gdk_color_context_get_pixels_incremental (GdkColorContext *cc,
+                                                          gushort         *reds,
+                                                          gushort         *greens,
+                                                          gushort         *blues,
+                                                          gint             ncolors,
+                                                          gint            *used,
+                                                          gulong          *colors,
+                                                          gint            *nallocated);
+
+gint            gdk_color_context_query_color            (GdkColorContext *cc,
+                                                          GdkColor        *color);
+gint            gdk_color_context_query_colors           (GdkColorContext *cc,
+                                                          GdkColor        *colors,
+                                                          gint             num_colors);
+
+gint            gdk_color_context_add_palette            (GdkColorContext *cc,
+                                                          GdkColor        *palette,
+                                                          gint             num_palette);
+
+void            gdk_color_context_init_dither            (GdkColorContext *cc);
+void            gdk_color_context_free_dither            (GdkColorContext *cc);
+
+gulong          gdk_color_context_get_pixel_from_palette (GdkColorContext *cc,
+                                                          gushort         *red,
+                                                          gushort         *green,
+                                                          gushort         *blue,
+                                                          gint            *failed);
+guchar          gdk_color_context_get_index_from_palette (GdkColorContext *cc,
+                                                          gint            *red,
+                                                          gint            *green,
+                                                          gint            *blue,
+                                                          gint            *failed);
+/* Regions
+ */
+
+GdkRegion*     gdk_region_new      (void);
+void          gdk_region_destroy   (GdkRegion     *region);
+
+void          gdk_region_get_clipbox(GdkRegion    *region,
+                                     GdkRectangle *rectangle);
+
+gboolean       gdk_region_empty            (GdkRegion     *region);
+gboolean       gdk_region_equal            (GdkRegion     *region1,
+                                    GdkRegion     *region2);
+gboolean       gdk_region_point_in  (GdkRegion    *region,
+                                    int                   x,
+                                    int                   y);
+GdkOverlapType gdk_region_rect_in   (GdkRegion    *region,
+                                    GdkRectangle  *rect);
+
+GdkRegion*     gdk_region_polygon   (GdkPoint      *points,
+                                    gint           npoints,
+                                    GdkFillRule    fill_rule);
+
+void          gdk_region_offset   (GdkRegion      *region,
+                                   gint           dx,
+                                   gint           dy);
+void          gdk_region_shrink   (GdkRegion      *region,
+                                   gint           dx,
+                                   gint           dy);
+
+GdkRegion*    gdk_region_union_with_rect  (GdkRegion     *region,
+                                          GdkRectangle   *rect);
+GdkRegion*    gdk_regions_intersect      (GdkRegion      *source1,
+                                          GdkRegion      *source2);
+GdkRegion*    gdk_regions_union                  (GdkRegion      *source1,
+                                          GdkRegion      *source2);
+GdkRegion*    gdk_regions_subtract       (GdkRegion      *source1,
+                                          GdkRegion      *source2);
+GdkRegion*    gdk_regions_xor            (GdkRegion      *source1,
+                                          GdkRegion      *source2);
+
+/* Miscellaneous */
+void     gdk_event_send_clientmessage_toall (GdkEvent    *event);
+gboolean gdk_event_send_client_message (GdkEvent    *event,
+                                       guint32      xid);
+
+/* Key values
+ */
+const gchar* gdk_keyval_name             (guint        keyval);
+guint       gdk_keyval_from_name         (const gchar *keyval_name);
+guint       gdk_keyval_to_upper          (guint        keyval);
+guint       gdk_keyval_to_lower          (guint        keyval);
+gboolean     gdk_keyval_is_upper         (guint        keyval);
+gboolean     gdk_keyval_is_lower         (guint        keyval);
+
+/* Threading
+ */
+
+GDKVAR GMutex *gdk_threads_mutex;
+
+void     gdk_threads_enter                (void);
+void     gdk_threads_leave                (void);
+
+#ifdef G_THREADS_ENABLED
+#  define GDK_THREADS_ENTER()  G_STMT_START {  \
+      if (gdk_threads_mutex)                   \
+        g_mutex_lock (gdk_threads_mutex);      \
+   } G_STMT_END
+#  define GDK_THREADS_LEAVE()  G_STMT_START {  \
+      if (gdk_threads_mutex)                   \
+        g_mutex_unlock (gdk_threads_mutex);    \
+   } G_STMT_END
+#else  /* !G_THREADS_ENABLED */
+#  define GDK_THREADS_ENTER()
+#  define GDK_THREADS_LEAVE()
+#endif /* !G_THREADS_ENABLED */
+
+#include <gdk/gdkrgb.h>
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GDK_H__ */
diff --git a/gdk/win32/gdkcc.c b/gdk/win32/gdkcc.c
new file mode 100644 (file)
index 0000000..8bbb7b3
--- /dev/null
@@ -0,0 +1,1610 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Color Context module
+ * Copyright 1994,1995 John L. Cwikla
+ * Copyright (C) 1997 by Ripley Software Development
+ * Copyright (C) 1997 by Federico Mena (port to Gtk/Gdk)
+ */
+
+/* Copyright 1994,1995 John L. Cwikla
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of John L. Cwikla or
+ * Wolfram Research, Inc not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written
+ * prior permission.  John L. Cwikla and Wolfram Research, Inc make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * John L. Cwikla and Wolfram Research, Inc disclaim all warranties with
+ * regard to this software, including all implied warranties of
+ * merchantability and fitness, in no event shall John L. Cwikla or
+ * Wolfram Research, Inc be liable for any special, indirect or
+ * consequential damages or any damages whatsoever resulting from loss of
+ * use, data or profits, whether in an action of contract, negligence or
+ * other tortious action, arising out of or in connection with the use or
+ * performance of this software.
+ *
+ * Author:
+ *  John L. Cwikla
+ *  X Programmer
+ *  Wolfram Research Inc.
+ *
+ *  cwikla@wri.com
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkx.h"
+
+#define MAX_IMAGE_COLORS 256
+
+
+static guint
+hash_color (gconstpointer key)
+{
+  const GdkColor *color = key;
+  
+  return (color->red * 33023 + color->green * 30013 + color->blue * 27011);
+}
+
+static gint
+compare_colors (gconstpointer a,
+               gconstpointer b)
+{
+  const GdkColor *aa = a;
+  const GdkColor *bb = b;
+  
+  return ((aa->red == bb->red) && (aa->green == bb->green) && (aa->blue == bb->blue));
+}
+
+static void
+free_hash_entry (gpointer key,
+                gpointer value,
+                gpointer user_data)
+{
+  g_free (key); /* key and value are the same GdkColor */
+}
+
+static int
+pixel_sort (const void *a, const void *b)
+{
+  return ((GdkColor *) a)->pixel - ((GdkColor *) b)->pixel;
+}
+
+/* XXX: This function does an XQueryColors() the hard way, because there is
+ * no corresponding function in Gdk.
+ */
+
+static void
+my_x_query_colors (GdkColormap *colormap,
+                  GdkColor    *colors,
+                  gint         ncolors)
+{
+  XColor *xcolors;
+  gint    i;
+  
+  for (i = 0; i < ncolors; i++)
+    {
+      PALETTEENTRY palentry;
+      
+      GetPaletteEntries (GDK_COLORMAP_XCOLORMAP (colormap)->palette, colors[i].pixel, 1, &palentry);
+      colors[i].red = (palentry.peRed * 65536) / 255;
+      colors[i].green = (palentry.peGreen * 65536) / 255;
+      colors[i].blue = (palentry.peBlue * 65536) / 255;
+    }
+}
+
+static void
+query_colors (GdkColorContext *cc)
+{
+  gint i;
+  GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
+  cc->cmap = g_new (GdkColor, cc->num_colors);
+  
+  for (i = 0; i < cc->num_colors; i++)
+    cc->cmap[i].pixel = cc->clut ? cc->clut[i] : ccp->std_cmap.base_pixel + i;
+  
+  my_x_query_colors (cc->colormap, cc->cmap, cc->num_colors);
+  
+  qsort (cc->cmap, cc->num_colors, sizeof (GdkColor), pixel_sort);
+}
+
+static void
+init_bw (GdkColorContext *cc)
+{
+  GdkColor color;
+  
+  g_warning ("init_bw: failed to allocate colors, falling back to black and white");
+  
+  cc->mode = GDK_CC_MODE_BW;
+  
+  color.red = color.green = color.blue = 0;
+  
+  if (!gdk_color_alloc (cc->colormap, &color))
+    cc->black_pixel = 0;
+  else
+    cc->black_pixel = color.pixel;
+  
+  color.red = color.green = color.blue = 0xffff;
+  
+  if (!gdk_color_alloc (cc->colormap, &color))
+    cc->white_pixel = cc->black_pixel ? 0 : 1;
+  else
+    cc->white_pixel = color.pixel;
+  
+  cc->num_colors = 2;
+}
+
+static void
+init_gray (GdkColorContext *cc)
+{
+  GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
+  GdkColor *clrs, *cstart;
+  gint i;
+  gdouble dinc;
+  
+  cc->num_colors = 256;                /* Bogus, but will never get here anyway? */
+  cc->clut = g_new (gulong, cc->num_colors);
+  cstart = g_new (GdkColor, cc->num_colors);
+  
+ retrygray:
+  
+  dinc = 65535.0 / (cc->num_colors - 1);
+  
+  clrs = cstart;
+  
+  for (i = 0; i < cc->num_colors; i++)
+    {
+      clrs->red = clrs->green = clrs->blue = dinc * i;
+      
+      if (!gdk_color_alloc (cc->colormap, clrs))
+       {
+         gdk_colors_free (cc->colormap, cc->clut, i, 0);
+         
+         cc->num_colors /= 2;
+         
+         if (cc->num_colors > 1)
+           goto retrygray;
+         else
+           {
+             g_free (cc->clut);
+             cc->clut = NULL;
+             init_bw (cc);
+             g_free (cstart);
+             return;
+           }
+       }
+      
+      cc->clut[i] = clrs++->pixel;
+    }
+  
+  g_free (cstart);
+  
+  /* XXX: is this the right thing to do? */
+  ccp->std_cmap.colormap = GDK_COLORMAP_XCOLORMAP (cc->colormap);
+  ccp->std_cmap.base_pixel = 0;
+  ccp->std_cmap.red_max = cc->num_colors - 1;
+  ccp->std_cmap.green_max = 0;
+  ccp->std_cmap.blue_max = 0;
+  ccp->std_cmap.red_mult = 1;
+  ccp->std_cmap.green_mult = 0;
+  ccp->std_cmap.blue_mult = 0;
+  
+  cc->white_pixel = 255;
+  cc->black_pixel = 0;
+
+  query_colors (cc);
+  
+  cc->mode = GDK_CC_MODE_MY_GRAY;
+}
+
+static void
+init_color (GdkColorContext *cc)
+{
+  GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
+  gint cubeval;
+  
+  cubeval = 1;
+  while ((cubeval * cubeval * cubeval) < GDK_VISUAL_XVISUAL (cc->visual)->map_entries)
+    cubeval++;
+  cubeval--;
+  
+  cc->num_colors = cubeval * cubeval * cubeval;
+  
+  ccp->std_cmap.red_max    = cubeval - 1;
+  ccp->std_cmap.green_max  = cubeval - 1;
+  ccp->std_cmap.blue_max   = cubeval - 1;
+  ccp->std_cmap.red_mult   = cubeval * cubeval;
+  ccp->std_cmap.green_mult = cubeval;
+  ccp->std_cmap.blue_mult  = 1;
+  ccp->std_cmap.base_pixel = 0;
+  
+  cc->white_pixel = 255;       /* ??? */
+  cc->black_pixel = 0;         /* ??? */
+  
+  /* a CLUT for storing allocated pixel indices */
+  
+  cc->max_colors = cc->num_colors;
+  cc->clut = g_new (gulong, cc->max_colors);
+  
+  for (cubeval = 0; cubeval < cc->max_colors; cubeval++)
+    cc->clut[cubeval] = cubeval;
+  
+  query_colors (cc);
+  
+  cc->mode = GDK_CC_MODE_STD_CMAP;
+}
+
+
+static void
+init_true_color (GdkColorContext *cc)
+{
+  GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
+  gulong rmask, gmask, bmask;
+  
+  cc->mode = GDK_CC_MODE_TRUE;
+  
+  /* Red */
+  
+  rmask = cc->masks.red = cc->visual->red_mask;
+  
+  cc->shifts.red = 0;
+  cc->bits.red = 0;
+  
+  while (!(rmask & 1))
+    {
+      rmask >>= 1;
+      cc->shifts.red++;
+    }
+  
+  while (rmask & 1)
+    {
+      rmask >>= 1;
+      cc->bits.red++;
+    }
+  
+  /* Green */
+  
+  gmask = cc->masks.green = cc->visual->green_mask;
+
+  cc->shifts.green = 0;
+  cc->bits.green = 0;
+  
+  while (!(gmask & 1))
+    {
+      gmask >>= 1;
+      cc->shifts.green++;
+    }
+  
+  while (gmask & 1)
+    {
+      gmask >>= 1;
+      cc->bits.green++;
+    }
+  
+  /* Blue */
+  
+  bmask = cc->masks.blue = cc->visual->blue_mask;
+  
+  cc->shifts.blue = 0;
+  cc->bits.blue = 0;
+  
+  while (!(bmask & 1))
+    {
+      bmask >>= 1;
+      cc->shifts.blue++;
+    }
+  
+  while (bmask & 1)
+    {
+      bmask >>= 1;
+      cc->bits.blue++;
+    }
+  
+  cc->num_colors = (cc->visual->red_mask | cc->visual->green_mask | cc->visual->blue_mask) + 1;
+  
+  cc->white_pixel = 0xffffff;
+  cc->black_pixel = 0;
+}
+
+static void
+init_palette (GdkColorContext *cc)
+{
+  /* restore correct mode for this cc */
+  switch (cc->visual->type)
+    {
+    case GDK_VISUAL_STATIC_GRAY:
+    case GDK_VISUAL_GRAYSCALE:
+      if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
+       cc->mode = GDK_CC_MODE_BW;
+      else
+       cc->mode = GDK_CC_MODE_MY_GRAY;
+      break;
+      
+    case GDK_VISUAL_TRUE_COLOR:
+      cc->mode = GDK_CC_MODE_TRUE;
+      break;
+      
+    case GDK_VISUAL_STATIC_COLOR:
+    case GDK_VISUAL_PSEUDO_COLOR:
+      cc->mode = GDK_CC_MODE_STD_CMAP;
+      break;
+      
+    default:
+      cc->mode = GDK_CC_MODE_UNDEFINED;
+      break;
+    }
+  
+  /* previous palette */
+  
+  if (cc->num_palette)
+    g_free (cc->palette);
+  
+  if (cc->fast_dither)
+    g_free (cc->fast_dither);
+  
+  /* clear hash table if present */
+  
+  if (cc->color_hash)
+    {
+      /* XXX: quick-and-dirty way to remove everything */
+      
+      g_hash_table_destroy (cc->color_hash);
+      cc->color_hash = g_hash_table_new (hash_color, compare_colors);
+    }
+  
+  cc->palette = NULL;
+  cc->num_palette = 0;
+  cc->fast_dither = NULL;
+}
+
+GdkColorContext *
+gdk_color_context_new (GdkVisual   *visual,
+                      GdkColormap *colormap)
+{
+  GdkColorContextPrivate *ccp;
+  gint use_private_colormap = FALSE; /* XXX: maybe restore full functionality later? */
+  GdkColorContext *cc;
+  gint retry_count;
+  GdkColormap *default_colormap;
+  
+  g_assert (visual != NULL);
+  g_assert (colormap != NULL);
+  
+  ccp = g_new (GdkColorContextPrivate, 1);
+  cc = (GdkColorContext *) ccp;
+  cc->visual = visual;
+  cc->colormap = colormap;
+  cc->clut = NULL;
+  cc->cmap = NULL;
+  cc->mode = GDK_CC_MODE_UNDEFINED;
+  cc->need_to_free_colormap = FALSE;
+  
+  cc->color_hash = NULL;
+  cc->palette = NULL;
+  cc->num_palette = 0;
+  cc->fast_dither = NULL;
+  
+  default_colormap = gdk_colormap_get_system ();
+  
+  retry_count = 0;
+  
+  while (retry_count < 2)
+    {
+      /* Only create a private colormap if the visual found isn't equal
+       * to the default visual and we don't have a private colormap,
+       * -or- if we are instructed to create a private colormap (which
+       * never is the case for XmHTML).
+       */
+      
+      if (use_private_colormap
+         || ((cc->visual != gdk_visual_get_system ()) /* default visual? */
+             && (GDK_COLORMAP_XCOLORMAP (colormap) == GDK_COLORMAP_XCOLORMAP (default_colormap))))
+       {
+         g_warning ("gdk_color_context_new: non-default visual detected, "
+                    "using private colormap");
+         
+         cc->colormap = gdk_colormap_new (cc->visual, FALSE);
+         
+         cc->need_to_free_colormap = (GDK_COLORMAP_XCOLORMAP (colormap)
+                                      != GDK_COLORMAP_XCOLORMAP (default_colormap));
+       }
+      
+      switch (visual->type)
+       {
+       case GDK_VISUAL_STATIC_GRAY:
+       case GDK_VISUAL_GRAYSCALE:
+         GDK_NOTE (COLOR_CONTEXT,
+                   g_message ("gdk_color_context_new: visual class is %s\n",
+                              (visual->type == GDK_VISUAL_STATIC_GRAY) ?
+                              "GDK_VISUAL_STATIC_GRAY" :
+                              "GDK_VISUAL_GRAYSCALE"));
+         
+         if (GDK_VISUAL_XVISUAL (cc->visual)->map_entries == 2)
+           init_bw (cc);
+         else
+           init_gray (cc);
+         break;
+         
+       case GDK_VISUAL_TRUE_COLOR: /* shifts */
+         GDK_NOTE (COLOR_CONTEXT,
+                   g_message ("gdk_color_context_new: visual class is GDK_VISUAL_TRUE_COLOR\n"));
+         
+         init_true_color (cc);
+         break;
+         
+       case GDK_VISUAL_STATIC_COLOR:
+       case GDK_VISUAL_PSEUDO_COLOR:
+         GDK_NOTE (COLOR_CONTEXT,
+                   g_message ("gdk_color_context_new: visual class is %s\n",
+                              (visual->type == GDK_VISUAL_STATIC_COLOR) ?
+                              "GDK_VISUAL_STATIC_COLOR" :
+                              "GDK_VISUAL_PSEUDO_COLOR"));
+         
+         init_color (cc);
+         break;
+         
+       default:
+         g_assert_not_reached ();
+       }
+      
+      if ((cc->mode == GDK_CC_MODE_BW) && (cc->visual->depth > 1))
+       {
+         use_private_colormap = TRUE;
+         retry_count++;
+       }
+      else
+       break;
+    }
+  
+  /* no. of colors allocated yet */
+  
+  cc->num_allocated = 0;
+  
+  GDK_NOTE (COLOR_CONTEXT,
+           g_message ("gdk_color_context_new: screen depth is %i, no. of colors is %i\n",
+                      cc->visual->depth, cc->num_colors));
+  
+  /* check if we need to initialize a hash table */
+  
+  if ((cc->mode == GDK_CC_MODE_STD_CMAP) || (cc->mode == GDK_CC_MODE_UNDEFINED))
+    cc->color_hash = g_hash_table_new (hash_color, compare_colors);
+  
+  return (GdkColorContext *) cc;
+}
+
+GdkColorContext *
+gdk_color_context_new_mono (GdkVisual   *visual,
+                           GdkColormap *colormap)
+{
+  GdkColorContextPrivate *ccp;
+  GdkColorContext *cc;
+  
+  g_assert (visual != NULL);
+  g_assert (colormap != NULL);
+  
+  cc = g_new (GdkColorContext, 1);
+  ccp = (GdkColorContextPrivate *) cc;
+  cc->visual = visual;
+  cc->colormap = colormap;
+  cc->clut = NULL;
+  cc->cmap = NULL;
+  cc->mode = GDK_CC_MODE_UNDEFINED;
+  cc->need_to_free_colormap = FALSE;
+  
+  init_bw (cc);
+  
+  return (GdkColorContext *) cc;
+}
+
+/* This doesn't currently free black/white, hmm... */
+
+void
+gdk_color_context_free (GdkColorContext *cc)
+{
+  g_assert (cc != NULL);
+  
+  if ((cc->visual->type == GDK_VISUAL_STATIC_COLOR)
+      || (cc->visual->type == GDK_VISUAL_PSEUDO_COLOR))
+    {
+      gdk_colors_free (cc->colormap, cc->clut, cc->num_allocated, 0);
+      g_free (cc->clut);
+    }
+  else if (cc->clut != NULL)
+    {
+      gdk_colors_free (cc->colormap, cc->clut, cc->num_colors, 0);
+      g_free (cc->clut);
+    }
+  
+  if (cc->cmap != NULL)
+    g_free (cc->cmap);
+  
+  if (cc->need_to_free_colormap)
+    gdk_colormap_unref (cc->colormap);
+  
+  /* free any palette that has been associated with this GdkColorContext */
+  
+  init_palette (cc);
+  
+  if (cc->color_hash)
+    {
+      g_hash_table_foreach (cc->color_hash,
+                           free_hash_entry,
+                           NULL);
+      g_hash_table_destroy (cc->color_hash);
+    }
+  
+  g_free (cc);
+}
+
+gulong
+gdk_color_context_get_pixel (GdkColorContext *cc,
+                            gushort          red,
+                            gushort          green,
+                            gushort          blue,
+                            gint            *failed)
+{
+  GdkColorContextPrivate *ccp = (GdkColorContextPrivate *) cc;
+  g_assert (cc != NULL);
+  g_assert (failed != NULL);
+  
+  *failed = FALSE;
+
+  switch (cc->mode)
+    {
+    case GDK_CC_MODE_BW:
+    {
+      gdouble value;
+      
+      value = (red / 65535.0 * 0.30
+              + green / 65535.0 * 0.59
+              + blue / 65535.0 * 0.11);
+      
+      if (value > 0.5)
+       return cc->white_pixel;
+      
+      return cc->black_pixel;
+    }
+    
+    case GDK_CC_MODE_MY_GRAY:
+    {
+      gulong ired, igreen, iblue;
+      
+      red   = red * 0.30 + green * 0.59 + blue * 0.11;
+      green = 0;
+      blue  = 0;
+      
+      if ((ired = red * (ccp->std_cmap.red_max + 1) / 0xffff) > ccp->std_cmap.red_max)
+       ired = ccp->std_cmap.red_max;
+      
+      ired *= ccp->std_cmap.red_mult;
+      
+      if ((igreen = green * (ccp->std_cmap.green_max + 1) / 0xffff) > ccp->std_cmap.green_max)
+       igreen = ccp->std_cmap.green_max;
+      
+      igreen *= ccp->std_cmap.green_mult;
+      
+      if ((iblue = blue * (ccp->std_cmap.blue_max + 1) / 0xffff) > ccp->std_cmap.blue_max)
+       iblue = ccp->std_cmap.blue_max;
+      
+      iblue *= ccp->std_cmap.blue_mult;
+      
+      if (cc->clut != NULL)
+       return cc->clut[ccp->std_cmap.base_pixel + ired + igreen + iblue];
+      
+      return ccp->std_cmap.base_pixel + ired + igreen + iblue;
+    }
+    
+    case GDK_CC_MODE_TRUE:
+    {
+      gulong ired, igreen, iblue;
+      
+      if (cc->clut == NULL)
+       {
+         red   >>= 16 - cc->bits.red;
+         green >>= 16 - cc->bits.green;
+         blue  >>= 16 - cc->bits.blue;
+         
+         ired   = (red << cc->shifts.red) & cc->masks.red;
+         igreen = (green << cc->shifts.green) & cc->masks.green;
+         iblue  = (blue << cc->shifts.blue) & cc->masks.blue;
+         
+         return ired | igreen | iblue;
+       }
+      
+      ired   = cc->clut[red * cc->max_entry / 65535] & cc->masks.red;
+      igreen = cc->clut[green * cc->max_entry / 65535] & cc->masks.green;
+      iblue  = cc->clut[blue * cc->max_entry / 65535] & cc->masks.blue;
+      
+      return ired | igreen | iblue;
+    }
+    
+    case GDK_CC_MODE_PALETTE:
+      return gdk_color_context_get_pixel_from_palette (cc, &red, &green, &blue, failed);
+      
+    case GDK_CC_MODE_STD_CMAP:
+    default:
+    {
+      GdkColor color;
+      GdkColor *result;
+      
+      color.red   = red;
+      color.green = green;
+      color.blue  = blue;
+      
+      result = g_hash_table_lookup (cc->color_hash, &color);
+      
+      if (!result)
+       {
+         color.red   = red;
+         color.green = green;
+         color.blue  = blue;
+         color.pixel = 0;
+         
+         if (!gdk_color_alloc (cc->colormap, &color))
+           *failed = TRUE;
+         else
+           {
+             GdkColor *cnew;
+             
+             /* XXX: the following comment comes directly from
+              * XCC.c.  I don't know if it is relevant for
+              * gdk_color_alloc() as it is for XAllocColor()
+              * - Federico
+              */
+             /*
+              * I can't figure this out entirely, but it *is* possible
+              * that XAllocColor succeeds, even if the number of
+              * allocations we've made exceeds the number of available
+              * colors in the current colormap. And therefore it
+              * might be necessary for us to resize the CLUT.
+              */
+             
+             if (cc->num_allocated == cc->max_colors)
+               {
+                 cc->max_colors *= 2;
+                 
+                 GDK_NOTE (COLOR_CONTEXT,
+                           g_message ("gdk_color_context_get_pixel: "
+                                      "resizing CLUT to %i entries\n",
+                                      cc->max_colors));
+                 
+                 cc->clut = g_realloc (cc->clut,
+                                       cc->max_colors * sizeof (gulong));
+               }
+             
+             /* Key and value are the same color structure */
+             
+             cnew = g_new (GdkColor, 1);
+             *cnew = color;
+             g_hash_table_insert (cc->color_hash, cnew, cnew);
+             
+             cc->clut[cc->num_allocated] = color.pixel;
+             cc->num_allocated++;
+             return color.pixel;
+           }
+       }
+      
+      return result->pixel;
+    }
+    }
+}
+
+void
+gdk_color_context_get_pixels (GdkColorContext *cc,
+                             gushort         *reds,
+                             gushort         *greens,
+                             gushort         *blues,
+                             gint             ncolors,
+                             gulong          *colors,
+                             gint            *nallocated)
+{
+  gint i, k, idx;
+  gint cmapsize, ncols = 0, nopen = 0, counter = 0;
+  gint bad_alloc = FALSE;
+  gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
+  GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
+#ifdef G_ENABLE_DEBUG  
+  gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
+#endif
+  g_assert (cc != NULL);
+  g_assert (reds != NULL);
+  g_assert (greens != NULL);
+  g_assert (blues != NULL);
+  g_assert (colors != NULL);
+  g_assert (nallocated != NULL);
+  
+  memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
+  memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
+  memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
+  
+  /* Will only have a value if used by the progressive image loader */
+  
+  ncols = *nallocated;
+  
+  *nallocated = 0;
+  
+  /* First allocate all pixels */
+  
+  for (i = 0; i < ncolors; i++)
+    {
+      /* colors[i] is only zero if the pixel at that location hasn't
+       * been allocated yet.  This is a sanity check required for proper
+       * color allocation by the progressive image loader
+       */
+      
+      if (colors[i] == 0)
+       {
+         defs[i].red   = reds[i];
+         defs[i].green = greens[i];
+         defs[i].blue  = blues[i];
+         
+         colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i],
+                                                  &bad_alloc);
+         
+         /* successfully allocated, store it */
+         
+         if (!bad_alloc)
+           {
+             defs[i].pixel = colors[i];
+             allocated[ncols++] = colors[i];
+           }
+         else
+           failed[nopen++] = i;
+       }
+    }
+  
+  *nallocated = ncols;
+  
+  /* all colors available, all done */
+  
+  if ((ncols == ncolors) || (nopen == 0))
+    {
+      GDK_NOTE (COLOR_CONTEXT,
+               g_message ("gdk_color_context_get_pixels: got all %i colors; "
+                          "(%i colors allocated so far)\n", ncolors, cc->num_allocated));
+      
+      return;
+    }
+  
+  /* The fun part.  We now try to allocate the colors we couldn't allocate
+   * directly.  The first step will map a color onto its nearest color
+   * that has been allocated (either by us or someone else).  If any colors
+   * remain unallocated, we map these onto the colors that we have allocated
+   * ourselves.
+   */
+  
+  /* read up to MAX_IMAGE_COLORS colors of the current colormap */
+  
+  cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
+  
+  /* see if the colormap has any colors to read */
+  
+  if (cmapsize < 0)
+    {
+      g_warning ("gdk_color_context_get_pixels: oops!  no colors available, "
+                "your images will look *really* ugly.");
+      
+      return;
+    }
+  
+#ifdef G_ENABLE_DEBUG
+  exact_col = ncols;
+#endif
+  
+  /* initialize pixels */
+  
+  for (i = 0; i < cmapsize; i++)
+    {
+      cmap[i].pixel = i;
+      cmap[i].red = cmap[i].green = cmap[i].blue = 0;
+    }
+  
+  /* read the colormap */
+  
+  my_x_query_colors (cc->colormap, cmap, cmapsize);
+  
+  /* get a close match for any unallocated colors */
+  
+  counter = nopen;
+  nopen = 0;
+  idx = 0;
+  
+  do
+    {
+      gint d, j, mdist, close, ri, gi, bi;
+      gint rd, gd, bd;
+      
+      i = failed[idx];
+      
+      mdist = 0x1000000;
+      close = -1;
+      
+      /* Store these vals.  Small performance increase as this skips three
+       * indexing operations in the loop code.
+       */
+      
+      ri = reds[i];
+      gi = greens[i];
+      bi = blues[i];
+      
+      /* Walk all colors in the colormap and see which one is the
+       * closest.  Uses plain least squares.
+       */
+      
+      for (j = 0; (j < cmapsize) && (mdist != 0); j++)
+       {
+         /* Don't replace these by shifts; the sign may get clobbered */
+         
+         rd = (ri - cmap[j].red) / 256;
+         gd = (gi - cmap[j].green) / 256;
+         bd = (bi - cmap[j].blue) / 256;
+         
+         d = rd * rd + gd * gd + bd * bd;
+         
+         if (d < mdist)
+           {
+             close = j;
+             mdist = d;
+           }
+       }
+      
+      if (close != -1)
+       {
+         rd = cmap[close].red;
+         gd = cmap[close].green;
+         bd = cmap[close].blue;
+         
+         /* allocate */
+         
+         colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
+         
+         /* store */
+         
+         if (!bad_alloc)
+           {
+             defs[i] = cmap[close];
+             defs[i].pixel = colors[i];
+             allocated[ncols++] = colors[i];
+#ifdef G_ENABLE_DEBUG
+             close_col++;
+#endif
+           } else
+             failed[nopen++] = i;
+       } else
+         failed[nopen++] = i;
+      /* deal with in next stage if allocation failed */
+    }
+  while (++idx < counter);
+  
+  *nallocated = ncols;
+  
+  /* This is the maximum no. of allocated colors.  See also the nopen == 0
+   * note above.
+   */
+  
+  if ((ncols == ncolors) || (nopen == 0))
+    {
+      GDK_NOTE (COLOR_CONTEXT,
+               g_message ("gdk_color_context_get_pixels: got %i colors, %i exact and "
+                          "%i close (%i colors allocated so far)\n",
+                          ncolors, exact_col, close_col, cc->num_allocated));
+      
+      return;
+    }
+  
+  /* Now map any remaining unallocated pixels into the colors we did get */
+  
+  idx = 0;
+  
+  do
+    {
+      gint d, mdist, close, ri, gi, bi;
+      gint j, rd, gd, bd;
+      
+      i = failed[idx];
+      
+      mdist = 0x1000000;
+      close = -1;
+      
+      /* store */
+      
+      ri = reds[i];
+      gi = greens[i];
+      bi = blues[i];
+      
+      /* search allocated colors */
+      
+      for (j = 0; (j < ncols) && (mdist != 0); j++)
+       {
+         k = allocated[j];
+         
+         /* Don't replace these by shifts; the sign may get clobbered */
+         
+         rd = (ri - defs[k].red) / 256;
+         gd = (gi - defs[k].green) / 256;
+         bd = (bi - defs[k].blue) / 256;
+         
+         d = rd * rd + gd * gd + bd * bd;
+         
+         if (d < mdist)
+           {
+             close = k;
+             mdist = d;
+           }
+       }
+      
+      if (close < 0)
+       {
+         /* too bad, map to black */
+         
+         defs[i].pixel = cc->black_pixel;
+         defs[i].red = defs[i].green = defs[i].blue = 0;
+#ifdef G_ENABLE_DEBUG
+         black_col++;
+#endif
+       }
+      else
+       {
+         defs[i] = defs[close];
+#ifdef G_ENABLE_DEBUG
+         subst_col++;
+#endif
+       }
+      
+      colors[i] = defs[i].pixel;
+    }
+  while (++idx < nopen);
+  
+  GDK_NOTE (COLOR_CONTEXT,
+           g_message ("gdk_color_context_get_pixels: got %i colors, %i exact, %i close, "
+                      "%i substituted, %i to black (%i colors allocated so far)\n",
+                      ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
+}
+
+void
+gdk_color_context_get_pixels_incremental (GdkColorContext *cc,
+                                         gushort         *reds,
+                                         gushort         *greens,
+                                         gushort         *blues,
+                                         gint             ncolors,
+                                         gint            *used,
+                                         gulong          *colors,
+                                         gint            *nallocated)
+{
+  gint i, k, idx;
+  gint cmapsize, ncols = 0, nopen = 0, counter = 0;
+  gint bad_alloc = FALSE;
+  gint failed[MAX_IMAGE_COLORS], allocated[MAX_IMAGE_COLORS];
+  GdkColor defs[MAX_IMAGE_COLORS], cmap[MAX_IMAGE_COLORS];
+#ifdef G_ENABLE_DEBUG  
+  gint exact_col = 0, subst_col = 0, close_col = 0, black_col = 0;
+#endif  
+  
+  g_assert (cc != NULL);
+  g_assert (reds != NULL);
+  g_assert (greens != NULL);
+  g_assert (blues != NULL);
+  g_assert (used != NULL);
+  g_assert (colors != NULL);
+  g_assert (nallocated != NULL);
+  
+  memset (defs, 0, MAX_IMAGE_COLORS * sizeof (GdkColor));
+  memset (failed, 0, MAX_IMAGE_COLORS * sizeof (gint));
+  memset (allocated, 0, MAX_IMAGE_COLORS * sizeof (gint));
+  
+  /* Will only have a value if used by the progressive image loader */
+  
+  ncols = *nallocated;
+  
+  *nallocated = 0;
+  
+  /* First allocate all pixels */
+  
+  for (i = 0; i < ncolors; i++)
+    {
+      /* used[i] is only -1 if the pixel at that location hasn't
+       * been allocated yet.  This is a sanity check required for proper
+       * color allocation by the progressive image loader.
+       * When colors[i] == 0 it indicates the slot is available for
+       * allocation.
+       */
+      
+      if (used[i] != FALSE)
+       {
+         if (colors[i] == 0)
+           {
+             defs[i].red   = reds[i];
+             defs[i].green = greens[i];
+             defs[i].blue  = blues[i];
+             
+             colors[i] = gdk_color_context_get_pixel (cc, reds[i], greens[i], blues[i], &bad_alloc);
+             
+             /* successfully allocated, store it */
+             
+             if (!bad_alloc)
+               {
+                 defs[i].pixel = colors[i];
+                 allocated[ncols++] = colors[i];
+               }
+             else
+               failed[nopen++] = i;
+           }
+#ifdef DEBUG
+         else
+           GDK_NOTE (COLOR_CONTEXT,
+                     g_message ("gdk_color_context_get_pixels_incremental: "
+                                "pixel at slot %i already allocated, skipping\n", i));
+#endif
+       }
+    }
+  
+  *nallocated = ncols;
+  
+  if ((ncols == ncolors) || (nopen == 0))
+    {
+      GDK_NOTE (COLOR_CONTEXT,
+               g_message ("gdk_color_context_get_pixels_incremental: got all %i colors "
+                          "(%i colors allocated so far)\n",
+                          ncolors, cc->num_allocated));
+      
+      return;
+    }
+  
+  cmapsize = MIN (cc->num_colors, MAX_IMAGE_COLORS);
+  
+  if (cmapsize < 0)
+    {
+      g_warning ("gdk_color_context_get_pixels_incremental: oops!  "
+                "No colors available images will look *really* ugly.");
+      return;
+    }
+  
+#ifdef G_ENABLE_DEBUG
+  exact_col = ncols;
+#endif
+  
+  /* initialize pixels */
+  
+  for (i = 0; i < cmapsize; i++)
+    {
+      cmap[i].pixel = i;
+      cmap[i].red = cmap[i].green = cmap[i].blue = 0;
+    }
+  
+  /* read */
+  
+  my_x_query_colors (cc->colormap, cmap, cmapsize);
+  
+  /* now match any unallocated colors */
+  
+  counter = nopen;
+  nopen = 0;
+  idx = 0;
+  
+  do
+    {
+      gint d, j, mdist, close, ri, gi, bi;
+      gint rd, gd, bd;
+      
+      i = failed[idx];
+      
+      mdist = 0x1000000;
+      close = -1;
+      
+      /* store */
+      
+      ri = reds[i];
+      gi = greens[i];
+      bi = blues[i];
+      
+      for (j = 0; (j < cmapsize) && (mdist != 0); j++)
+       {
+         /* Don't replace these by shifts; the sign may get clobbered */
+         
+         rd = (ri - cmap[j].red) / 256;
+         gd = (gi - cmap[j].green) / 256;
+         bd = (bi - cmap[j].blue) / 256;
+         
+         d = rd * rd + gd * gd + bd * bd;
+         
+         if (d < mdist)
+           {
+             close = j;
+             mdist = d;
+           }
+       }
+      
+      if (close != -1)
+       {
+         rd = cmap[close].red;
+         gd = cmap[close].green;
+         bd = cmap[close].blue;
+         
+         /* allocate */
+         
+         colors[i] = gdk_color_context_get_pixel (cc, rd, gd, bd, &bad_alloc);
+         
+         /* store */
+         
+         if (!bad_alloc)
+           {
+             defs[i] = cmap[close];
+             defs[i].pixel = colors[i];
+             allocated[ncols++] = colors[i];
+#ifdef G_ENABLE_DEBUG
+             close_col++;
+#endif
+           }
+         else
+           failed[nopen++] = i;
+       }
+      else
+       failed[nopen++] = i;
+      /* deal with in next stage if allocation failed */
+    }
+  while (++idx < counter);
+  
+  *nallocated = ncols;
+  
+  if ((ncols == ncolors) || (nopen == 0))
+    {
+      GDK_NOTE (COLOR_CONTEXT,
+               g_message ("gdk_color_context_get_pixels_incremental: "
+                          "got %i colors, %i exact and %i close "
+                          "(%i colors allocated so far)\n",
+                          ncolors, exact_col, close_col, cc->num_allocated));
+      
+      return;
+    }
+  
+  /* map remaining unallocated pixels into colors we did get */
+  
+  idx = 0;
+  
+  do
+    {
+      gint d, mdist, close, ri, gi, bi;
+      gint j, rd, gd, bd;
+      
+      i = failed[idx];
+      
+      mdist = 0x1000000;
+      close = -1;
+      
+      ri = reds[i];
+      gi = greens[i];
+      bi = blues[i];
+      
+      /* search allocated colors */
+      
+      for (j = 0; (j < ncols) && (mdist != 0); j++)
+       {
+         k = allocated[j];
+         
+         /* downscale */
+         /* Don't replace these by shifts; the sign may get clobbered */
+         
+         rd = (ri - defs[k].red) / 256;
+         gd = (gi - defs[k].green) / 256;
+         bd = (bi - defs[k].blue) / 256;
+         
+         d = rd * rd + gd * gd + bd * bd;
+         
+         if (d < mdist)
+           {
+             close = k;
+             mdist = d;
+           }
+       }
+      
+      if (close < 0)
+       {
+         /* too bad, map to black */
+         
+         defs[i].pixel = cc->black_pixel;
+         defs[i].red = defs[i].green = defs[i].blue = 0;
+#ifdef G_ENABLE_DEBUG
+         black_col++;
+#endif
+       }
+      else
+       {
+         defs[i] = defs[close];
+#ifdef G_ENABLE_DEBUG
+         subst_col++;
+#endif
+       }
+      
+      colors[i] = defs[i].pixel;
+    }
+  while (++idx < nopen);
+  
+  GDK_NOTE (COLOR_CONTEXT,
+           g_message ("gdk_color_context_get_pixels_incremental: "
+                      "got %i colors, %i exact, %i close, %i substituted, %i to black "
+                      "(%i colors allocated so far)\n",
+                      ncolors, exact_col, close_col, subst_col, black_col, cc->num_allocated));
+}
+
+gint
+gdk_color_context_query_color (GdkColorContext *cc,
+                              GdkColor        *color)
+{
+  return gdk_color_context_query_colors (cc, color, 1);
+}
+
+gint
+gdk_color_context_query_colors (GdkColorContext *cc,
+                               GdkColor        *colors,
+                               gint             num_colors)
+{
+  gint i;
+  GdkColor *tc;
+  
+  g_assert (cc != NULL);
+  g_assert (colors != NULL);
+  
+  switch (cc->mode)
+    {
+    case GDK_CC_MODE_BW:
+      for (i = 0, tc = colors; i < num_colors; i++, tc++)
+       {
+         if (tc->pixel == cc->white_pixel)
+           tc->red = tc->green = tc->blue = 65535;
+         else
+           tc->red = tc->green = tc->blue = 0;
+       }
+      break;
+      
+    case GDK_CC_MODE_TRUE:
+      if (cc->clut == NULL)
+       for (i = 0, tc = colors; i < num_colors; i++, tc++)
+         {
+           tc->red   = ((tc->pixel & cc->masks.red) >> cc->shifts.red) << (16 - cc->bits.red);
+           tc->green = ((tc->pixel & cc->masks.green) >> cc->shifts.green) << (16 - cc->bits.green);
+           tc->blue  = ((tc->pixel & cc->masks.blue) >> cc->shifts.blue) << (16 - cc->bits.blue);
+         }
+      else
+       {
+         my_x_query_colors (cc->colormap, colors, num_colors);
+         return 1;
+       }
+      break;
+      
+    case GDK_CC_MODE_STD_CMAP:
+    default:
+      if (cc->cmap == NULL)
+       {
+         my_x_query_colors (cc->colormap, colors, num_colors);
+         return 1;
+       }
+      else
+       {
+         gint first, last, half;
+         gulong half_pixel;
+         
+         for (i = 0, tc = colors; i < num_colors; i++)
+           {
+             first = 0;
+             last = cc->num_colors - 1;
+             
+             while (first <= last)
+               {
+                 half = (first + last) / 2;
+                 half_pixel = cc->cmap[half].pixel;
+                 
+                 if (tc->pixel == half_pixel)
+                   {
+                     tc->red   = cc->cmap[half].red;
+                     tc->green = cc->cmap[half].green;
+                     tc->blue  = cc->cmap[half].blue;
+                     first = last + 1; /* false break */
+                   }
+                 else
+                   {
+                     if (tc->pixel > half_pixel)
+                       first = half + 1;
+                     else
+                       last = half - 1;
+                   }
+               }
+           }
+         return 1;
+       }
+      break;
+    }
+  return 1;
+}
+
+gint
+gdk_color_context_add_palette (GdkColorContext *cc,
+                              GdkColor        *palette,
+                              gint             num_palette)
+{
+  gint i, j, erg;
+  gushort r, g, b;
+  gulong pixel[1];
+  
+  g_assert (cc != NULL);
+  
+  /* initialize this palette (will also erase previous palette as well) */
+  
+  init_palette (cc);
+  
+  /* restore previous mode if we aren't adding a new palette */
+  
+  if (num_palette == 0)
+    {
+      /* GDK_CC_MODE_STD_CMAP uses a hash table, so we'd better initialize one */
+      
+      /* XXX: here, the hash table is already initialized */
+      
+      return 0;
+    }
+  
+  /* Initialize a hash table for this palette (we need one for allocating
+   * the pixels in the palette using the current settings)
+   */
+  
+  if (cc->color_hash == NULL)
+    cc->color_hash = g_hash_table_new (hash_color, compare_colors);
+  
+  /* copy incoming palette */
+  
+  cc->palette = g_new0(GdkColor, num_palette);
+  
+  j = 0;
+
+  for (i = 0; i < num_palette; i++)
+    {
+      erg = 0;
+      pixel[0] = 0;
+      
+      /* try to allocate this color */
+      
+      r = palette[i].red;
+      g = palette[i].green;
+      b = palette[i].blue;
+      
+      gdk_color_context_get_pixels (cc, &r, &g, &b, 1, pixel, &erg);
+      
+      /* only store if we succeed */
+      
+      if (erg)
+       {
+         /* store in palette */
+         
+         cc->palette[j].red   = r;
+         cc->palette[j].green = g;
+         cc->palette[j].blue  = b;
+         cc->palette[j].pixel = pixel[0];
+         
+         /* move to next slot */
+         
+         j++;
+       }
+    }
+  
+  /* resize to fit */
+  
+  if (j != num_palette)
+    cc->palette = g_realloc (cc->palette, j * sizeof (GdkColor));
+  
+  /* clear the hash table, we don't use it when dithering */
+  
+  if (cc->color_hash)
+    {
+      g_hash_table_destroy (cc->color_hash);
+      cc->color_hash = NULL;
+    }
+  
+  /* store real palette size */
+  
+  cc->num_palette = j;
+  
+  /* switch to palette mode */
+  
+  cc->mode = GDK_CC_MODE_PALETTE;
+  
+  /* sort palette */
+  
+  qsort (cc->palette, cc->num_palette, sizeof (GdkColor), pixel_sort);
+  
+  cc->fast_dither = NULL;
+  
+  return j;
+}
+
+void
+gdk_color_context_init_dither (GdkColorContext *cc)
+{
+  gint rr, gg, bb, err, erg, erb;
+  gint success = FALSE;
+  
+  g_assert (cc != NULL);
+  
+  /* now we can initialize the fast dither matrix */
+  
+  if (cc->fast_dither == NULL)
+    cc->fast_dither = g_new (GdkColorContextDither, 1);
+  
+  /* Fill it.  We ignore unsuccessful allocations, they are just mapped
+   * to black instead */
+  
+  for (rr = 0; rr < 32; rr++)
+    for (gg = 0; gg < 32; gg++)
+      for (bb = 0; bb < 32; bb++)
+       {
+         err = (rr << 3) | (rr >> 2);
+         erg = (gg << 3) | (gg >> 2);
+         erb = (bb << 3) | (bb >> 2);
+         
+         cc->fast_dither->fast_rgb[rr][gg][bb] =
+           gdk_color_context_get_index_from_palette (cc, &err, &erg, &erb, &success);
+         cc->fast_dither->fast_err[rr][gg][bb] = err;
+         cc->fast_dither->fast_erg[rr][gg][bb] = erg;
+         cc->fast_dither->fast_erb[rr][gg][bb] = erb;
+       }
+}
+
+void
+gdk_color_context_free_dither (GdkColorContext *cc)
+{
+  g_assert (cc != NULL);
+  
+  if (cc->fast_dither)
+    g_free (cc->fast_dither);
+  
+  cc->fast_dither = NULL;
+}
+
+gulong
+gdk_color_context_get_pixel_from_palette (GdkColorContext *cc,
+                                         gushort         *red,
+                                         gushort         *green,
+                                         gushort         *blue,
+                                         gint            *failed)
+{
+  gulong pixel = 0;
+  gint dif, dr, dg, db, j = -1;
+  gint mindif = 0x7fffffff;
+  gint err = 0, erg = 0, erb = 0;
+  gint i;
+  
+  g_assert (cc != NULL);
+  g_assert (red != NULL);
+  g_assert (green != NULL);
+  g_assert (blue != NULL);
+  g_assert (failed != NULL);
+  
+  *failed = FALSE;
+  
+  for (i = 0; i < cc->num_palette; i++)
+    {
+      dr = *red - cc->palette[i].red;
+      dg = *green - cc->palette[i].green;
+      db = *blue - cc->palette[i].blue;
+      
+      dif = dr * dr + dg * dg + db * db;
+      
+      if (dif < mindif)
+       {
+         mindif = dif;
+         j = i;
+         pixel = cc->palette[i].pixel;
+         err = dr;
+         erg = dg;
+         erb = db;
+         
+         if (mindif == 0)
+           break;
+       }
+    }
+  
+  /* we failed to map onto a color */
+  
+  if (j == -1)
+    *failed = TRUE;
+  else
+    {
+      *red   = ABS (err);
+      *green = ABS (erg);
+      *blue  = ABS (erb);
+    }
+  
+  return pixel;
+}
+
+guchar
+gdk_color_context_get_index_from_palette (GdkColorContext *cc,
+                                         gint            *red,
+                                         gint            *green,
+                                         gint            *blue,
+                                         gint            *failed)
+{
+  gint dif, dr, dg, db, j = -1;
+  gint mindif = 0x7fffffff;
+  gint err = 0, erg = 0, erb = 0;
+  gint i;
+  
+  g_assert (cc != NULL);
+  g_assert (red != NULL);
+  g_assert (green != NULL);
+  g_assert (blue != NULL);
+  g_assert (failed != NULL);
+  
+  *failed = FALSE;
+  
+  for (i = 0; i < cc->num_palette; i++)
+    {
+      dr = *red - cc->palette[i].red;
+      dg = *green - cc->palette[i].green;
+      db = *blue - cc->palette[i].blue;
+      
+      dif = dr * dr + dg * dg + db * db;
+      
+      if (dif < mindif)
+       {
+         mindif = dif;
+         j = i;
+         err = dr;
+         erg = dg;
+         erb = db;
+         
+         if (mindif == 0)
+           break;
+       }
+    }
+  
+  /* we failed to map onto a color */
+  
+  if (j == -1)
+    {
+      *failed = TRUE;
+      j = 0;
+    }
+  else
+    {
+      /* return error fractions */
+      
+      *red   = err;
+      *green = erg;
+      *blue  = erb;
+    }
+  
+  return j;
+}
diff --git a/gdk/win32/gdkcolor-win32.c b/gdk/win32/gdkcolor-win32.c
new file mode 100644 (file)
index 0000000..4b81f24
--- /dev/null
@@ -0,0 +1,2443 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkx.h"
+
+#ifdef _MSC_VER
+#define strcasecmp stricmp
+#endif
+
+static gint  gdk_colormap_match_color (GdkColormap *cmap,
+                                      GdkColor    *color,
+                                      const gchar *available);
+static void  gdk_colormap_add         (GdkColormap *cmap);
+static void  gdk_colormap_remove      (GdkColormap *cmap);
+static guint gdk_colormap_hash        (Colormap    *cmap);
+static gint  gdk_colormap_cmp         (Colormap    *a,
+                                      Colormap    *b);
+static void gdk_colormap_real_destroy (GdkColormap *colormap);
+
+static GHashTable *colormap_hash = NULL;
+
+static Status
+alloc_color_cells(Colormap      colormap,
+                 gboolean      contig,
+                 unsigned long plane_masks_return[],
+                 unsigned int  nplanes,
+                 unsigned long pixels_return[],
+                 unsigned int  npixels)
+{
+  unsigned int i, nfree, iret;
+
+  nfree = 0;
+  for (i = 0; i < colormap->size && nfree < npixels; i++)
+    if (!colormap->in_use[i])
+      nfree++;
+
+  if (colormap->size + npixels - nfree > colormap->sizepalette)
+    {
+      g_warning ("alloc_color_cells: too large palette: %d",
+                colormap->size + npixels);
+      return FALSE;
+    }
+
+  iret = 0;
+  for (i = 0; i < colormap->size && iret < npixels; i++)
+    if (!colormap->in_use[i])
+      {
+       colormap->in_use[i] = TRUE;
+       pixels_return[iret] = i;
+       iret++;
+      }
+
+  if (nfree < npixels)
+    {
+      int nmore = npixels - nfree;
+
+      /* I don't understand why, if the code below in #if 0 is
+        enabled, gdkrgb fails miserably. The palette doesn't get
+        realized correctly. There doesn't seem to be any harm done by
+        keeping this code out, either.  */
+#ifdef SOME_STRANGE_BUG
+      if (!ResizePalette (colormap->palette, colormap->size + nmore))
+       {
+         g_warning ("alloc_color_cells: ResizePalette to %d failed",
+                    colormap->size + nmore);
+         return FALSE;
+       }
+      g_print("alloc_color_cells: %#x to %d\n",
+             colormap->palette, colormap->size + nmore);
+#endif
+      for (i = colormap->size; i < colormap->size + nmore; i++)
+       {
+         pixels_return[iret] = i;
+         iret++;
+         colormap->in_use[i] = TRUE;
+       }
+#ifdef SOME_STRANGE_BUG
+      colormap->size += nmore;
+#endif
+    }
+  return TRUE;
+}
+
+/* The following functions are from Tk8.0, but heavily modified.
+   Here are tk's licensing terms. I hope these terms don't conflict
+   with the GNU Library General Public License? They shouldn't, as
+   they are looser that the GLPL, yes? */
+
+/*
+This software is copyrighted by the Regents of the University of
+California, Sun Microsystems, Inc., and other parties.  The following
+terms apply to all files associated with the software unless explicitly
+disclaimed in individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+GOVERNMENT USE: If you are acquiring this software on behalf of the
+U.S. government, the Government shall have only "Restricted Rights"
+in the software and related documentation as defined in the Federal 
+Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
+are acquiring the software on behalf of the Department of Defense, the
+software shall be classified as "Commercial Computer Software" and the
+Government shall have only "Restricted Rights" as defined in Clause
+252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
+authors grant the U.S. Government and others acting in its behalf
+permission to use and distribute the software in accordance with the
+terms specified in this license.
+*/
+/*
+ *----------------------------------------------------------------------
+ *
+ * XAllocColor --
+ *
+ *     Find the closest available color to the specified XColor.
+ *
+ * Results:
+ *     Updates the color argument and returns 1 on success.  Otherwise
+ *     returns 0.
+ *
+ * Side effects:
+ *     Allocates a new color in the palette.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+alloc_color(Colormap  colormap,
+           XColor   *color,
+           guint    *pixelp)
+{
+  PALETTEENTRY entry, closeEntry;
+  HDC hdc;
+  unsigned int i;
+    
+  entry = *color;
+  entry.peFlags = 0;
+
+  if (colormap->rc_palette)
+    {
+      COLORREF newPixel, closePixel;
+      UINT index;
+
+      /*
+       * Find the nearest existing palette entry.
+       */
+       
+      newPixel = RGB (entry.peRed, entry.peGreen, entry.peBlue);
+      index = GetNearestPaletteIndex (colormap->palette, newPixel);
+      GetPaletteEntries (colormap->palette, index, 1, &closeEntry);
+      closePixel = RGB (closeEntry.peRed, closeEntry.peGreen,
+                       closeEntry.peBlue);
+
+      if (newPixel != closePixel)
+       {
+         /* Not a perfect match. */
+         if (!colormap->in_use[index])
+           {
+             /* It was a free'd entry anyway, so we can use it, and
+                set it to the correct color. */
+             if (SetPaletteEntries (colormap->palette, index, 1, &entry) == 0)
+               g_warning ("alloc_color: SetPaletteEntries #1 failed");
+           }
+         else
+           {
+             /* The close entry found is in use, so search for a
+                unused slot. */
+                
+             for (i = 0; i < colormap->size; i++)
+               if (!colormap->in_use[i])
+                 {
+                   /* A free slot, use it. */
+                   if (SetPaletteEntries (colormap->palette,
+                                          index, 1, &entry) == 0)
+                     g_warning ("alloc_color: SetPaletteEntries #2 failed");
+                   index = i;
+                   break;
+                 }
+             if (i == colormap->size)
+               {
+                 /* No free slots found. If the palette isn't maximal
+                    yet, grow it. */
+                 if (colormap->size == colormap->sizepalette)
+                   {
+                     /* The palette is maximal, and no free slots available,
+                        so use the close entry, then, dammit. */
+                     *color = closeEntry;
+                   }
+                 else
+                   {
+                     /* There is room to grow the palette. */
+                     index = colormap->size;
+                     colormap->size++;
+                     if (!ResizePalette (colormap->palette, colormap->size))
+                       g_warning ("alloc_color: ResizePalette to %d failed",
+                                  colormap->size);
+                     if (SetPaletteEntries (colormap->palette, index, 1, &entry) == 0)
+                       g_warning ("alloc_color: SetPaletteEntries #3 failed");
+                   }
+               }
+           }
+         colormap->stale = TRUE;
+       }
+      else
+       {
+         /* We got a match, so use it. */
+       }
+
+      *pixelp = index;
+      colormap->in_use[index] = TRUE;
+#if 0
+      g_print("alloc_color from %#x: index %d for %02x %02x %02x\n",
+             colormap->palette, index,
+             entry.peRed, entry.peGreen, entry.peBlue);
+#endif
+    }
+  else
+    {
+      /*
+       * Determine what color will actually be used on non-colormap systems.
+       */
+      *pixelp = GetNearestColor (gdk_DC, RGB(entry.peRed, entry.peGreen, entry.peBlue));
+      
+      color->peRed = GetRValue (*pixelp);
+      color->peGreen = GetGValue (*pixelp);
+      color->peBlue = GetBValue (*pixelp);
+    }
+  
+  return 1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XFreeColors --
+ *
+ *     Deallocate a block of colors.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Removes entries for the current palette and compacts the
+ *     remaining set.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+XFreeColors(Colormap colormap,
+           gulong  *pixels,
+           gint     npixels,
+           gulong   planes)
+{
+  gint i;
+  PALETTEENTRY entries[256];
+
+  /*
+   * We don't have to do anything for non-palette devices.
+   */
+  
+  if (colormap->rc_palette)
+    {
+      int npal;
+      int lowestpixel = 256;
+      int highestpixel = -1;
+
+      npal = GetPaletteEntries (colormap->palette, 0, 256, entries);
+      for (i = 0; i < npixels; i++)
+       {
+         int pixel = pixels[i];
+
+         if (pixel < lowestpixel)
+           lowestpixel = pixel;
+         if (pixel > highestpixel)
+           highestpixel = pixel;
+
+         colormap->in_use[pixel] = FALSE;
+
+         entries[pixel] = entries[0];
+       }
+#if 0
+      if (SetPaletteEntries (colormap->palette, lowestpixel,
+                            highestpixel - lowestpixel + 1,
+                            entries + lowestpixel) == 0)
+       g_warning ("XFreeColors: SetPaletteEntries failed");
+#endif
+      colormap->stale = TRUE;
+#if 0
+      g_print("XFreeColors %#x lowestpixel = %d, highestpixel = %d\n",
+             colormap->palette, lowestpixel, highestpixel);
+#endif
+    }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XCreateColormap --
+ *
+ *     Allocate a new colormap.
+ *
+ * Results:
+ *     Returns a newly allocated colormap.
+ *
+ * Side effects:
+ *     Allocates an empty palette and color list.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Colormap
+create_colormap (HWND     w,
+                Visual  *visual,
+                int      alloc)
+{
+  char logPalBuf[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)];
+  LOGPALETTE *logPalettePtr;
+  PALETTEENTRY *entryPtr;
+  Colormap colormap;
+  guint i;
+  HPALETTE sysPal;
+  HDC hdc;
+
+  /* Should the alloc parameter do something? */
+
+
+  /* Allocate a starting palette with all of the reserved colors. */
+  
+  logPalettePtr = (LOGPALETTE *) logPalBuf;
+  logPalettePtr->palVersion = 0x300;
+  sysPal = (HPALETTE) GetStockObject (DEFAULT_PALETTE);
+  logPalettePtr->palNumEntries =
+    GetPaletteEntries (sysPal, 0, 256, logPalettePtr->palPalEntry);
+  
+  colormap = (Colormap) g_new (ColormapStruct, 1);
+  colormap->size = logPalettePtr->palNumEntries;
+  colormap->stale = TRUE;
+  colormap->palette = CreatePalette (logPalettePtr);
+  hdc = GetDC (NULL);
+  colormap->rc_palette = ((GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE) != 0);
+  if (colormap->rc_palette)
+    {
+      colormap->sizepalette = GetDeviceCaps (hdc, SIZEPALETTE);
+      colormap->in_use = g_new (gboolean, colormap->sizepalette);
+      /* Mark static colors in use. */
+      for (i = 0; i < logPalettePtr->palNumEntries; i++)
+       colormap->in_use[i] = TRUE;
+      /* Mark rest not in use */
+      for (i = logPalettePtr->palNumEntries; i < colormap->sizepalette; i++)
+       colormap->in_use[i] = FALSE;
+    }
+  ReleaseDC (NULL, hdc);
+
+  return colormap;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XFreeColormap --
+ *
+ *     Frees the resources associated with the given colormap.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Deletes the palette associated with the colormap.  Note that
+ *     the palette must not be selected into a device context when
+ *     this occurs.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+XFreeColormap(Colormap  colormap)
+{
+  if (!DeleteObject (colormap->palette))
+    {
+      g_error ("Unable to free colormap, palette is still selected.");
+    }
+  g_free (colormap);
+}
+
+typedef struct {
+    char *name;
+    unsigned char red;
+    unsigned char green;
+    unsigned char blue;
+} XColorEntry;
+
+static XColorEntry xColors[] = {
+    { "alice blue", 240, 248, 255 },
+    { "AliceBlue", 240, 248, 255 },
+    { "antique white", 250, 235, 215 },
+    { "AntiqueWhite", 250, 235, 215 },
+    { "AntiqueWhite1", 255, 239, 219 },
+    { "AntiqueWhite2", 238, 223, 204 },
+    { "AntiqueWhite3", 205, 192, 176 },
+    { "AntiqueWhite4", 139, 131, 120 },
+    { "aquamarine", 127, 255, 212 },
+    { "aquamarine1", 127, 255, 212 },
+    { "aquamarine2", 118, 238, 198 },
+    { "aquamarine3", 102, 205, 170 },
+    { "aquamarine4", 69, 139, 116 },
+    { "azure", 240, 255, 255 },
+    { "azure1", 240, 255, 255 },
+    { "azure2", 224, 238, 238 },
+    { "azure3", 193, 205, 205 },
+    { "azure4", 131, 139, 139 },
+    { "beige", 245, 245, 220 },
+    { "bisque", 255, 228, 196 },
+    { "bisque1", 255, 228, 196 },
+    { "bisque2", 238, 213, 183 },
+    { "bisque3", 205, 183, 158 },
+    { "bisque4", 139, 125, 107 },
+    { "black", 0, 0, 0 },
+    { "blanched almond", 255, 235, 205 },
+    { "BlanchedAlmond", 255, 235, 205 },
+    { "blue", 0, 0, 255 },
+    { "blue violet", 138, 43, 226 },
+    { "blue1", 0, 0, 255 },
+    { "blue2", 0, 0, 238 },
+    { "blue3", 0, 0, 205 },
+    { "blue4", 0, 0, 139 },
+    { "BlueViolet", 138, 43, 226 },
+    { "brown", 165, 42, 42 },
+    { "brown1", 255, 64, 64 },
+    { "brown2", 238, 59, 59 },
+    { "brown3", 205, 51, 51 },
+    { "brown4", 139, 35, 35 },
+    { "burlywood", 222, 184, 135 },
+    { "burlywood1", 255, 211, 155 },
+    { "burlywood2", 238, 197, 145 },
+    { "burlywood3", 205, 170, 125 },
+    { "burlywood4", 139, 115, 85 },
+    { "cadet blue", 95, 158, 160 },
+    { "CadetBlue", 95, 158, 160 },
+    { "CadetBlue1", 152, 245, 255 },
+    { "CadetBlue2", 142, 229, 238 },
+    { "CadetBlue3", 122, 197, 205 },
+    { "CadetBlue4", 83, 134, 139 },
+    { "chartreuse", 127, 255, 0 },
+    { "chartreuse1", 127, 255, 0 },
+    { "chartreuse2", 118, 238, 0 },
+    { "chartreuse3", 102, 205, 0 },
+    { "chartreuse4", 69, 139, 0 },
+    { "chocolate", 210, 105, 30 },
+    { "chocolate1", 255, 127, 36 },
+    { "chocolate2", 238, 118, 33 },
+    { "chocolate3", 205, 102, 29 },
+    { "chocolate4", 139, 69, 19 },
+    { "coral", 255, 127, 80 },
+    { "coral1", 255, 114, 86 },
+    { "coral2", 238, 106, 80 },
+    { "coral3", 205, 91, 69 },
+    { "coral4", 139, 62, 47 },
+    { "cornflower blue", 100, 149, 237 },
+    { "CornflowerBlue", 100, 149, 237 },
+    { "cornsilk", 255, 248, 220 },
+    { "cornsilk1", 255, 248, 220 },
+    { "cornsilk2", 238, 232, 205 },
+    { "cornsilk3", 205, 200, 177 },
+    { "cornsilk4", 139, 136, 120 },
+    { "cyan", 0, 255, 255 },
+    { "cyan1", 0, 255, 255 },
+    { "cyan2", 0, 238, 238 },
+    { "cyan3", 0, 205, 205 },
+    { "cyan4", 0, 139, 139 },
+    { "dark blue", 0, 0, 139 },
+    { "dark cyan", 0, 139, 139 },
+    { "dark goldenrod", 184, 134, 11 },
+    { "dark gray", 169, 169, 169 },
+    { "dark green", 0, 100, 0 },
+    { "dark grey", 169, 169, 169 },
+    { "dark khaki", 189, 183, 107 },
+    { "dark magenta", 139, 0, 139 },
+    { "dark olive green", 85, 107, 47 },
+    { "dark orange", 255, 140, 0 },
+    { "dark orchid", 153, 50, 204 },
+    { "dark red", 139, 0, 0 },
+    { "dark salmon", 233, 150, 122 },
+    { "dark sea green", 143, 188, 143 },
+    { "dark slate blue", 72, 61, 139 },
+    { "dark slate gray", 47, 79, 79 },
+    { "dark slate grey", 47, 79, 79 },
+    { "dark turquoise", 0, 206, 209 },
+    { "dark violet", 148, 0, 211 },
+    { "DarkBlue", 0, 0, 139 },
+    { "DarkCyan", 0, 139, 139 },
+    { "DarkGoldenrod", 184, 134, 11 },
+    { "DarkGoldenrod1", 255, 185, 15 },
+    { "DarkGoldenrod2", 238, 173, 14 },
+    { "DarkGoldenrod3", 205, 149, 12 },
+    { "DarkGoldenrod4", 139, 101, 8 },
+    { "DarkGray", 169, 169, 169 },
+    { "DarkGreen", 0, 100, 0 },
+    { "DarkGrey", 169, 169, 169 },
+    { "DarkKhaki", 189, 183, 107 },
+    { "DarkMagenta", 139, 0, 139 },
+    { "DarkOliveGreen", 85, 107, 47 },
+    { "DarkOliveGreen1", 202, 255, 112 },
+    { "DarkOliveGreen2", 188, 238, 104 },
+    { "DarkOliveGreen3", 162, 205, 90 },
+    { "DarkOliveGreen4", 110, 139, 61 },
+    { "DarkOrange", 255, 140, 0 },
+    { "DarkOrange1", 255, 127, 0 },
+    { "DarkOrange2", 238, 118, 0 },
+    { "DarkOrange3", 205, 102, 0 },
+    { "DarkOrange4", 139, 69, 0 },
+    { "DarkOrchid", 153, 50, 204 },
+    { "DarkOrchid1", 191, 62, 255 },
+    { "DarkOrchid2", 178, 58, 238 },
+    { "DarkOrchid3", 154, 50, 205 },
+    { "DarkOrchid4", 104, 34, 139 },
+    { "DarkRed", 139, 0, 0 },
+    { "DarkSalmon", 233, 150, 122 },
+    { "DarkSeaGreen", 143, 188, 143 },
+    { "DarkSeaGreen1", 193, 255, 193 },
+    { "DarkSeaGreen2", 180, 238, 180 },
+    { "DarkSeaGreen3", 155, 205, 155 },
+    { "DarkSeaGreen4", 105, 139, 105 },
+    { "DarkSlateBlue", 72, 61, 139 },
+    { "DarkSlateGray", 47, 79, 79 },
+    { "DarkSlateGray1", 151, 255, 255 },
+    { "DarkSlateGray2", 141, 238, 238 },
+    { "DarkSlateGray3", 121, 205, 205 },
+    { "DarkSlateGray4", 82, 139, 139 },
+    { "DarkSlateGrey", 47, 79, 79 },
+    { "DarkTurquoise", 0, 206, 209 },
+    { "DarkViolet", 148, 0, 211 },
+    { "deep pink", 255, 20, 147 },
+    { "deep sky blue", 0, 191, 255 },
+    { "DeepPink", 255, 20, 147 },
+    { "DeepPink1", 255, 20, 147 },
+    { "DeepPink2", 238, 18, 137 },
+    { "DeepPink3", 205, 16, 118 },
+    { "DeepPink4", 139, 10, 80 },
+    { "DeepSkyBlue", 0, 191, 255 },
+    { "DeepSkyBlue1", 0, 191, 255 },
+    { "DeepSkyBlue2", 0, 178, 238 },
+    { "DeepSkyBlue3", 0, 154, 205 },
+    { "DeepSkyBlue4", 0, 104, 139 },
+    { "dim gray", 105, 105, 105 },
+    { "dim grey", 105, 105, 105 },
+    { "DimGray", 105, 105, 105 },
+    { "DimGrey", 105, 105, 105 },
+    { "dodger blue", 30, 144, 255 },
+    { "DodgerBlue", 30, 144, 255 },
+    { "DodgerBlue1", 30, 144, 255 },
+    { "DodgerBlue2", 28, 134, 238 },
+    { "DodgerBlue3", 24, 116, 205 },
+    { "DodgerBlue4", 16, 78, 139 },
+    { "firebrick", 178, 34, 34 },
+    { "firebrick1", 255, 48, 48 },
+    { "firebrick2", 238, 44, 44 },
+    { "firebrick3", 205, 38, 38 },
+    { "firebrick4", 139, 26, 26 },
+    { "floral white", 255, 250, 240 },
+    { "FloralWhite", 255, 250, 240 },
+    { "forest green", 34, 139, 34 },
+    { "ForestGreen", 34, 139, 34 },
+    { "gainsboro", 220, 220, 220 },
+    { "ghost white", 248, 248, 255 },
+    { "GhostWhite", 248, 248, 255 },
+    { "gold", 255, 215, 0 },
+    { "gold1", 255, 215, 0 },
+    { "gold2", 238, 201, 0 },
+    { "gold3", 205, 173, 0 },
+    { "gold4", 139, 117, 0 },
+    { "goldenrod", 218, 165, 32 },
+    { "goldenrod1", 255, 193, 37 },
+    { "goldenrod2", 238, 180, 34 },
+    { "goldenrod3", 205, 155, 29 },
+    { "goldenrod4", 139, 105, 20 },
+    { "gray", 190, 190, 190 },
+    { "gray0", 0, 0, 0 },
+    { "gray1", 3, 3, 3 },
+    { "gray10", 26, 26, 26 },
+    { "gray100", 255, 255, 255 },
+    { "gray11", 28, 28, 28 },
+    { "gray12", 31, 31, 31 },
+    { "gray13", 33, 33, 33 },
+    { "gray14", 36, 36, 36 },
+    { "gray15", 38, 38, 38 },
+    { "gray16", 41, 41, 41 },
+    { "gray17", 43, 43, 43 },
+    { "gray18", 46, 46, 46 },
+    { "gray19", 48, 48, 48 },
+    { "gray2", 5, 5, 5 },
+    { "gray20", 51, 51, 51 },
+    { "gray21", 54, 54, 54 },
+    { "gray22", 56, 56, 56 },
+    { "gray23", 59, 59, 59 },
+    { "gray24", 61, 61, 61 },
+    { "gray25", 64, 64, 64 },
+    { "gray26", 66, 66, 66 },
+    { "gray27", 69, 69, 69 },
+    { "gray28", 71, 71, 71 },
+    { "gray29", 74, 74, 74 },
+    { "gray3", 8, 8, 8 },
+    { "gray30", 77, 77, 77 },
+    { "gray31", 79, 79, 79 },
+    { "gray32", 82, 82, 82 },
+    { "gray33", 84, 84, 84 },
+    { "gray34", 87, 87, 87 },
+    { "gray35", 89, 89, 89 },
+    { "gray36", 92, 92, 92 },
+    { "gray37", 94, 94, 94 },
+    { "gray38", 97, 97, 97 },
+    { "gray39", 99, 99, 99 },
+    { "gray4", 10, 10, 10 },
+    { "gray40", 102, 102, 102 },
+    { "gray41", 105, 105, 105 },
+    { "gray42", 107, 107, 107 },
+    { "gray43", 110, 110, 110 },
+    { "gray44", 112, 112, 112 },
+    { "gray45", 115, 115, 115 },
+    { "gray46", 117, 117, 117 },
+    { "gray47", 120, 120, 120 },
+    { "gray48", 122, 122, 122 },
+    { "gray49", 125, 125, 125 },
+    { "gray5", 13, 13, 13 },
+    { "gray50", 127, 127, 127 },
+    { "gray51", 130, 130, 130 },
+    { "gray52", 133, 133, 133 },
+    { "gray53", 135, 135, 135 },
+    { "gray54", 138, 138, 138 },
+    { "gray55", 140, 140, 140 },
+    { "gray56", 143, 143, 143 },
+    { "gray57", 145, 145, 145 },
+    { "gray58", 148, 148, 148 },
+    { "gray59", 150, 150, 150 },
+    { "gray6", 15, 15, 15 },
+    { "gray60", 153, 153, 153 },
+    { "gray61", 156, 156, 156 },
+    { "gray62", 158, 158, 158 },
+    { "gray63", 161, 161, 161 },
+    { "gray64", 163, 163, 163 },
+    { "gray65", 166, 166, 166 },
+    { "gray66", 168, 168, 168 },
+    { "gray67", 171, 171, 171 },
+    { "gray68", 173, 173, 173 },
+    { "gray69", 176, 176, 176 },
+    { "gray7", 18, 18, 18 },
+    { "gray70", 179, 179, 179 },
+    { "gray71", 181, 181, 181 },
+    { "gray72", 184, 184, 184 },
+    { "gray73", 186, 186, 186 },
+    { "gray74", 189, 189, 189 },
+    { "gray75", 191, 191, 191 },
+    { "gray76", 194, 194, 194 },
+    { "gray77", 196, 196, 196 },
+    { "gray78", 199, 199, 199 },
+    { "gray79", 201, 201, 201 },
+    { "gray8", 20, 20, 20 },
+    { "gray80", 204, 204, 204 },
+    { "gray81", 207, 207, 207 },
+    { "gray82", 209, 209, 209 },
+    { "gray83", 212, 212, 212 },
+    { "gray84", 214, 214, 214 },
+    { "gray85", 217, 217, 217 },
+    { "gray86", 219, 219, 219 },
+    { "gray87", 222, 222, 222 },
+    { "gray88", 224, 224, 224 },
+    { "gray89", 227, 227, 227 },
+    { "gray9", 23, 23, 23 },
+    { "gray90", 229, 229, 229 },
+    { "gray91", 232, 232, 232 },
+    { "gray92", 235, 235, 235 },
+    { "gray93", 237, 237, 237 },
+    { "gray94", 240, 240, 240 },
+    { "gray95", 242, 242, 242 },
+    { "gray96", 245, 245, 245 },
+    { "gray97", 247, 247, 247 },
+    { "gray98", 250, 250, 250 },
+    { "gray99", 252, 252, 252 },
+    { "green", 0, 255, 0 },
+    { "green yellow", 173, 255, 47 },
+    { "green1", 0, 255, 0 },
+    { "green2", 0, 238, 0 },
+    { "green3", 0, 205, 0 },
+    { "green4", 0, 139, 0 },
+    { "GreenYellow", 173, 255, 47 },
+    { "grey", 190, 190, 190 },
+    { "grey0", 0, 0, 0 },
+    { "grey1", 3, 3, 3 },
+    { "grey10", 26, 26, 26 },
+    { "grey100", 255, 255, 255 },
+    { "grey11", 28, 28, 28 },
+    { "grey12", 31, 31, 31 },
+    { "grey13", 33, 33, 33 },
+    { "grey14", 36, 36, 36 },
+    { "grey15", 38, 38, 38 },
+    { "grey16", 41, 41, 41 },
+    { "grey17", 43, 43, 43 },
+    { "grey18", 46, 46, 46 },
+    { "grey19", 48, 48, 48 },
+    { "grey2", 5, 5, 5 },
+    { "grey20", 51, 51, 51 },
+    { "grey21", 54, 54, 54 },
+    { "grey22", 56, 56, 56 },
+    { "grey23", 59, 59, 59 },
+    { "grey24", 61, 61, 61 },
+    { "grey25", 64, 64, 64 },
+    { "grey26", 66, 66, 66 },
+    { "grey27", 69, 69, 69 },
+    { "grey28", 71, 71, 71 },
+    { "grey29", 74, 74, 74 },
+    { "grey3", 8, 8, 8 },
+    { "grey30", 77, 77, 77 },
+    { "grey31", 79, 79, 79 },
+    { "grey32", 82, 82, 82 },
+    { "grey33", 84, 84, 84 },
+    { "grey34", 87, 87, 87 },
+    { "grey35", 89, 89, 89 },
+    { "grey36", 92, 92, 92 },
+    { "grey37", 94, 94, 94 },
+    { "grey38", 97, 97, 97 },
+    { "grey39", 99, 99, 99 },
+    { "grey4", 10, 10, 10 },
+    { "grey40", 102, 102, 102 },
+    { "grey41", 105, 105, 105 },
+    { "grey42", 107, 107, 107 },
+    { "grey43", 110, 110, 110 },
+    { "grey44", 112, 112, 112 },
+    { "grey45", 115, 115, 115 },
+    { "grey46", 117, 117, 117 },
+    { "grey47", 120, 120, 120 },
+    { "grey48", 122, 122, 122 },
+    { "grey49", 125, 125, 125 },
+    { "grey5", 13, 13, 13 },
+    { "grey50", 127, 127, 127 },
+    { "grey51", 130, 130, 130 },
+    { "grey52", 133, 133, 133 },
+    { "grey53", 135, 135, 135 },
+    { "grey54", 138, 138, 138 },
+    { "grey55", 140, 140, 140 },
+    { "grey56", 143, 143, 143 },
+    { "grey57", 145, 145, 145 },
+    { "grey58", 148, 148, 148 },
+    { "grey59", 150, 150, 150 },
+    { "grey6", 15, 15, 15 },
+    { "grey60", 153, 153, 153 },
+    { "grey61", 156, 156, 156 },
+    { "grey62", 158, 158, 158 },
+    { "grey63", 161, 161, 161 },
+    { "grey64", 163, 163, 163 },
+    { "grey65", 166, 166, 166 },
+    { "grey66", 168, 168, 168 },
+    { "grey67", 171, 171, 171 },
+    { "grey68", 173, 173, 173 },
+    { "grey69", 176, 176, 176 },
+    { "grey7", 18, 18, 18 },
+    { "grey70", 179, 179, 179 },
+    { "grey71", 181, 181, 181 },
+    { "grey72", 184, 184, 184 },
+    { "grey73", 186, 186, 186 },
+    { "grey74", 189, 189, 189 },
+    { "grey75", 191, 191, 191 },
+    { "grey76", 194, 194, 194 },
+    { "grey77", 196, 196, 196 },
+    { "grey78", 199, 199, 199 },
+    { "grey79", 201, 201, 201 },
+    { "grey8", 20, 20, 20 },
+    { "grey80", 204, 204, 204 },
+    { "grey81", 207, 207, 207 },
+    { "grey82", 209, 209, 209 },
+    { "grey83", 212, 212, 212 },
+    { "grey84", 214, 214, 214 },
+    { "grey85", 217, 217, 217 },
+    { "grey86", 219, 219, 219 },
+    { "grey87", 222, 222, 222 },
+    { "grey88", 224, 224, 224 },
+    { "grey89", 227, 227, 227 },
+    { "grey9", 23, 23, 23 },
+    { "grey90", 229, 229, 229 },
+    { "grey91", 232, 232, 232 },
+    { "grey92", 235, 235, 235 },
+    { "grey93", 237, 237, 237 },
+    { "grey94", 240, 240, 240 },
+    { "grey95", 242, 242, 242 },
+    { "grey96", 245, 245, 245 },
+    { "grey97", 247, 247, 247 },
+    { "grey98", 250, 250, 250 },
+    { "grey99", 252, 252, 252 },
+    { "honeydew", 240, 255, 240 },
+    { "honeydew1", 240, 255, 240 },
+    { "honeydew2", 224, 238, 224 },
+    { "honeydew3", 193, 205, 193 },
+    { "honeydew4", 131, 139, 131 },
+    { "hot pink", 255, 105, 180 },
+    { "HotPink", 255, 105, 180 },
+    { "HotPink1", 255, 110, 180 },
+    { "HotPink2", 238, 106, 167 },
+    { "HotPink3", 205, 96, 144 },
+    { "HotPink4", 139, 58, 98 },
+    { "indian red", 205, 92, 92 },
+    { "IndianRed", 205, 92, 92 },
+    { "IndianRed1", 255, 106, 106 },
+    { "IndianRed2", 238, 99, 99 },
+    { "IndianRed3", 205, 85, 85 },
+    { "IndianRed4", 139, 58, 58 },
+    { "ivory", 255, 255, 240 },
+    { "ivory1", 255, 255, 240 },
+    { "ivory2", 238, 238, 224 },
+    { "ivory3", 205, 205, 193 },
+    { "ivory4", 139, 139, 131 },
+    { "khaki", 240, 230, 140 },
+    { "khaki1", 255, 246, 143 },
+    { "khaki2", 238, 230, 133 },
+    { "khaki3", 205, 198, 115 },
+    { "khaki4", 139, 134, 78 },
+    { "lavender", 230, 230, 250 },
+    { "lavender blush", 255, 240, 245 },
+    { "LavenderBlush", 255, 240, 245 },
+    { "LavenderBlush1", 255, 240, 245 },
+    { "LavenderBlush2", 238, 224, 229 },
+    { "LavenderBlush3", 205, 193, 197 },
+    { "LavenderBlush4", 139, 131, 134 },
+    { "lawn green", 124, 252, 0 },
+    { "LawnGreen", 124, 252, 0 },
+    { "lemon chiffon", 255, 250, 205 },
+    { "LemonChiffon", 255, 250, 205 },
+    { "LemonChiffon1", 255, 250, 205 },
+    { "LemonChiffon2", 238, 233, 191 },
+    { "LemonChiffon3", 205, 201, 165 },
+    { "LemonChiffon4", 139, 137, 112 },
+    { "light blue", 173, 216, 230 },
+    { "light coral", 240, 128, 128 },
+    { "light cyan", 224, 255, 255 },
+    { "light goldenrod", 238, 221, 130 },
+    { "light goldenrod yellow", 250, 250, 210 },
+    { "light gray", 211, 211, 211 },
+    { "light green", 144, 238, 144 },
+    { "light grey", 211, 211, 211 },
+    { "light pink", 255, 182, 193 },
+    { "light salmon", 255, 160, 122 },
+    { "light sea green", 32, 178, 170 },
+    { "light sky blue", 135, 206, 250 },
+    { "light slate blue", 132, 112, 255 },
+    { "light slate gray", 119, 136, 153 },
+    { "light slate grey", 119, 136, 153 },
+    { "light steel blue", 176, 196, 222 },
+    { "light yellow", 255, 255, 224 },
+    { "LightBlue", 173, 216, 230 },
+    { "LightBlue1", 191, 239, 255 },
+    { "LightBlue2", 178, 223, 238 },
+    { "LightBlue3", 154, 192, 205 },
+    { "LightBlue4", 104, 131, 139 },
+    { "LightCoral", 240, 128, 128 },
+    { "LightCyan", 224, 255, 255 },
+    { "LightCyan1", 224, 255, 255 },
+    { "LightCyan2", 209, 238, 238 },
+    { "LightCyan3", 180, 205, 205 },
+    { "LightCyan4", 122, 139, 139 },
+    { "LightGoldenrod", 238, 221, 130 },
+    { "LightGoldenrod1", 255, 236, 139 },
+    { "LightGoldenrod2", 238, 220, 130 },
+    { "LightGoldenrod3", 205, 190, 112 },
+    { "LightGoldenrod4", 139, 129, 76 },
+    { "LightGoldenrodYellow", 250, 250, 210 },
+    { "LightGray", 211, 211, 211 },
+    { "LightGreen", 144, 238, 144 },
+    { "LightGrey", 211, 211, 211 },
+    { "LightPink", 255, 182, 193 },
+    { "LightPink1", 255, 174, 185 },
+    { "LightPink2", 238, 162, 173 },
+    { "LightPink3", 205, 140, 149 },
+    { "LightPink4", 139, 95, 101 },
+    { "LightSalmon", 255, 160, 122 },
+    { "LightSalmon1", 255, 160, 122 },
+    { "LightSalmon2", 238, 149, 114 },
+    { "LightSalmon3", 205, 129, 98 },
+    { "LightSalmon4", 139, 87, 66 },
+    { "LightSeaGreen", 32, 178, 170 },
+    { "LightSkyBlue", 135, 206, 250 },
+    { "LightSkyBlue1", 176, 226, 255 },
+    { "LightSkyBlue2", 164, 211, 238 },
+    { "LightSkyBlue3", 141, 182, 205 },
+    { "LightSkyBlue4", 96, 123, 139 },
+    { "LightSlateBlue", 132, 112, 255 },
+    { "LightSlateGray", 119, 136, 153 },
+    { "LightSlateGrey", 119, 136, 153 },
+    { "LightSteelBlue", 176, 196, 222 },
+    { "LightSteelBlue1", 202, 225, 255 },
+    { "LightSteelBlue2", 188, 210, 238 },
+    { "LightSteelBlue3", 162, 181, 205 },
+    { "LightSteelBlue4", 110, 123, 139 },
+    { "LightYellow", 255, 255, 224 },
+    { "LightYellow1", 255, 255, 224 },
+    { "LightYellow2", 238, 238, 209 },
+    { "LightYellow3", 205, 205, 180 },
+    { "LightYellow4", 139, 139, 122 },
+    { "lime green", 50, 205, 50 },
+    { "LimeGreen", 50, 205, 50 },
+    { "linen", 250, 240, 230 },
+    { "magenta", 255, 0, 255 },
+    { "magenta1", 255, 0, 255 },
+    { "magenta2", 238, 0, 238 },
+    { "magenta3", 205, 0, 205 },
+    { "magenta4", 139, 0, 139 },
+    { "maroon", 176, 48, 96 },
+    { "maroon1", 255, 52, 179 },
+    { "maroon2", 238, 48, 167 },
+    { "maroon3", 205, 41, 144 },
+    { "maroon4", 139, 28, 98 },
+    { "medium aquamarine", 102, 205, 170 },
+    { "medium blue", 0, 0, 205 },
+    { "medium orchid", 186, 85, 211 },
+    { "medium purple", 147, 112, 219 },
+    { "medium sea green", 60, 179, 113 },
+    { "medium slate blue", 123, 104, 238 },
+    { "medium spring green", 0, 250, 154 },
+    { "medium turquoise", 72, 209, 204 },
+    { "medium violet red", 199, 21, 133 },
+    { "MediumAquamarine", 102, 205, 170 },
+    { "MediumBlue", 0, 0, 205 },
+    { "MediumOrchid", 186, 85, 211 },
+    { "MediumOrchid1", 224, 102, 255 },
+    { "MediumOrchid2", 209, 95, 238 },
+    { "MediumOrchid3", 180, 82, 205 },
+    { "MediumOrchid4", 122, 55, 139 },
+    { "MediumPurple", 147, 112, 219 },
+    { "MediumPurple1", 171, 130, 255 },
+    { "MediumPurple2", 159, 121, 238 },
+    { "MediumPurple3", 137, 104, 205 },
+    { "MediumPurple4", 93, 71, 139 },
+    { "MediumSeaGreen", 60, 179, 113 },
+    { "MediumSlateBlue", 123, 104, 238 },
+    { "MediumSpringGreen", 0, 250, 154 },
+    { "MediumTurquoise", 72, 209, 204 },
+    { "MediumVioletRed", 199, 21, 133 },
+    { "midnight blue", 25, 25, 112 },
+    { "MidnightBlue", 25, 25, 112 },
+    { "mint cream", 245, 255, 250 },
+    { "MintCream", 245, 255, 250 },
+    { "misty rose", 255, 228, 225 },
+    { "MistyRose", 255, 228, 225 },
+    { "MistyRose1", 255, 228, 225 },
+    { "MistyRose2", 238, 213, 210 },
+    { "MistyRose3", 205, 183, 181 },
+    { "MistyRose4", 139, 125, 123 },
+    { "moccasin", 255, 228, 181 },
+    { "navajo white", 255, 222, 173 },
+    { "NavajoWhite", 255, 222, 173 },
+    { "NavajoWhite1", 255, 222, 173 },
+    { "NavajoWhite2", 238, 207, 161 },
+    { "NavajoWhite3", 205, 179, 139 },
+    { "NavajoWhite4", 139, 121, 94 },
+    { "navy", 0, 0, 128 },
+    { "navy blue", 0, 0, 128 },
+    { "NavyBlue", 0, 0, 128 },
+    { "old lace", 253, 245, 230 },
+    { "OldLace", 253, 245, 230 },
+    { "olive drab", 107, 142, 35 },
+    { "OliveDrab", 107, 142, 35 },
+    { "OliveDrab1", 192, 255, 62 },
+    { "OliveDrab2", 179, 238, 58 },
+    { "OliveDrab3", 154, 205, 50 },
+    { "OliveDrab4", 105, 139, 34 },
+    { "orange", 255, 165, 0 },
+    { "orange red", 255, 69, 0 },
+    { "orange1", 255, 165, 0 },
+    { "orange2", 238, 154, 0 },
+    { "orange3", 205, 133, 0 },
+    { "orange4", 139, 90, 0 },
+    { "OrangeRed", 255, 69, 0 },
+    { "OrangeRed1", 255, 69, 0 },
+    { "OrangeRed2", 238, 64, 0 },
+    { "OrangeRed3", 205, 55, 0 },
+    { "OrangeRed4", 139, 37, 0 },
+    { "orchid", 218, 112, 214 },
+    { "orchid1", 255, 131, 250 },
+    { "orchid2", 238, 122, 233 },
+    { "orchid3", 205, 105, 201 },
+    { "orchid4", 139, 71, 137 },
+    { "pale goldenrod", 238, 232, 170 },
+    { "pale green", 152, 251, 152 },
+    { "pale turquoise", 175, 238, 238 },
+    { "pale violet red", 219, 112, 147 },
+    { "PaleGoldenrod", 238, 232, 170 },
+    { "PaleGreen", 152, 251, 152 },
+    { "PaleGreen1", 154, 255, 154 },
+    { "PaleGreen2", 144, 238, 144 },
+    { "PaleGreen3", 124, 205, 124 },
+    { "PaleGreen4", 84, 139, 84 },
+    { "PaleTurquoise", 175, 238, 238 },
+    { "PaleTurquoise1", 187, 255, 255 },
+    { "PaleTurquoise2", 174, 238, 238 },
+    { "PaleTurquoise3", 150, 205, 205 },
+    { "PaleTurquoise4", 102, 139, 139 },
+    { "PaleVioletRed", 219, 112, 147 },
+    { "PaleVioletRed1", 255, 130, 171 },
+    { "PaleVioletRed2", 238, 121, 159 },
+    { "PaleVioletRed3", 205, 104, 137 },
+    { "PaleVioletRed4", 139, 71, 93 },
+    { "papaya whip", 255, 239, 213 },
+    { "PapayaWhip", 255, 239, 213 },
+    { "peach puff", 255, 218, 185 },
+    { "PeachPuff", 255, 218, 185 },
+    { "PeachPuff1", 255, 218, 185 },
+    { "PeachPuff2", 238, 203, 173 },
+    { "PeachPuff3", 205, 175, 149 },
+    { "PeachPuff4", 139, 119, 101 },
+    { "peru", 205, 133, 63 },
+    { "pink", 255, 192, 203 },
+    { "pink1", 255, 181, 197 },
+    { "pink2", 238, 169, 184 },
+    { "pink3", 205, 145, 158 },
+    { "pink4", 139, 99, 108 },
+    { "plum", 221, 160, 221 },
+    { "plum1", 255, 187, 255 },
+    { "plum2", 238, 174, 238 },
+    { "plum3", 205, 150, 205 },
+    { "plum4", 139, 102, 139 },
+    { "powder blue", 176, 224, 230 },
+    { "PowderBlue", 176, 224, 230 },
+    { "purple", 160, 32, 240 },
+    { "purple1", 155, 48, 255 },
+    { "purple2", 145, 44, 238 },
+    { "purple3", 125, 38, 205 },
+    { "purple4", 85, 26, 139 },
+    { "red", 255, 0, 0 },
+    { "red1", 255, 0, 0 },
+    { "red2", 238, 0, 0 },
+    { "red3", 205, 0, 0 },
+    { "red4", 139, 0, 0 },
+    { "rosy brown", 188, 143, 143 },
+    { "RosyBrown", 188, 143, 143 },
+    { "RosyBrown1", 255, 193, 193 },
+    { "RosyBrown2", 238, 180, 180 },
+    { "RosyBrown3", 205, 155, 155 },
+    { "RosyBrown4", 139, 105, 105 },
+    { "royal blue", 65, 105, 225 },
+    { "RoyalBlue", 65, 105, 225 },
+    { "RoyalBlue1", 72, 118, 255 },
+    { "RoyalBlue2", 67, 110, 238 },
+    { "RoyalBlue3", 58, 95, 205 },
+    { "RoyalBlue4", 39, 64, 139 },
+    { "saddle brown", 139, 69, 19 },
+    { "SaddleBrown", 139, 69, 19 },
+    { "salmon", 250, 128, 114 },
+    { "salmon1", 255, 140, 105 },
+    { "salmon2", 238, 130, 98 },
+    { "salmon3", 205, 112, 84 },
+    { "salmon4", 139, 76, 57 },
+    { "sandy brown", 244, 164, 96 },
+    { "SandyBrown", 244, 164, 96 },
+    { "sea green", 46, 139, 87 },
+    { "SeaGreen", 46, 139, 87 },
+    { "SeaGreen1", 84, 255, 159 },
+    { "SeaGreen2", 78, 238, 148 },
+    { "SeaGreen3", 67, 205, 128 },
+    { "SeaGreen4", 46, 139, 87 },
+    { "seashell", 255, 245, 238 },
+    { "seashell1", 255, 245, 238 },
+    { "seashell2", 238, 229, 222 },
+    { "seashell3", 205, 197, 191 },
+    { "seashell4", 139, 134, 130 },
+    { "sienna", 160, 82, 45 },
+    { "sienna1", 255, 130, 71 },
+    { "sienna2", 238, 121, 66 },
+    { "sienna3", 205, 104, 57 },
+    { "sienna4", 139, 71, 38 },
+    { "sky blue", 135, 206, 235 },
+    { "SkyBlue", 135, 206, 235 },
+    { "SkyBlue1", 135, 206, 255 },
+    { "SkyBlue2", 126, 192, 238 },
+    { "SkyBlue3", 108, 166, 205 },
+    { "SkyBlue4", 74, 112, 139 },
+    { "slate blue", 106, 90, 205 },
+    { "slate gray", 112, 128, 144 },
+    { "slate grey", 112, 128, 144 },
+    { "SlateBlue", 106, 90, 205 },
+    { "SlateBlue1", 131, 111, 255 },
+    { "SlateBlue2", 122, 103, 238 },
+    { "SlateBlue3", 105, 89, 205 },
+    { "SlateBlue4", 71, 60, 139 },
+    { "SlateGray", 112, 128, 144 },
+    { "SlateGray1", 198, 226, 255 },
+    { "SlateGray2", 185, 211, 238 },
+    { "SlateGray3", 159, 182, 205 },
+    { "SlateGray4", 108, 123, 139 },
+    { "SlateGrey", 112, 128, 144 },
+    { "snow", 255, 250, 250 },
+    { "snow1", 255, 250, 250 },
+    { "snow2", 238, 233, 233 },
+    { "snow3", 205, 201, 201 },
+    { "snow4", 139, 137, 137 },
+    { "spring green", 0, 255, 127 },
+    { "SpringGreen", 0, 255, 127 },
+    { "SpringGreen1", 0, 255, 127 },
+    { "SpringGreen2", 0, 238, 118 },
+    { "SpringGreen3", 0, 205, 102 },
+    { "SpringGreen4", 0, 139, 69 },
+    { "steel blue", 70, 130, 180 },
+    { "SteelBlue", 70, 130, 180 },
+    { "SteelBlue1", 99, 184, 255 },
+    { "SteelBlue2", 92, 172, 238 },
+    { "SteelBlue3", 79, 148, 205 },
+    { "SteelBlue4", 54, 100, 139 },
+    { "tan", 210, 180, 140 },
+    { "tan1", 255, 165, 79 },
+    { "tan2", 238, 154, 73 },
+    { "tan3", 205, 133, 63 },
+    { "tan4", 139, 90, 43 },
+    { "thistle", 216, 191, 216 },
+    { "thistle1", 255, 225, 255 },
+    { "thistle2", 238, 210, 238 },
+    { "thistle3", 205, 181, 205 },
+    { "thistle4", 139, 123, 139 },
+    { "tomato", 255, 99, 71 },
+    { "tomato1", 255, 99, 71 },
+    { "tomato2", 238, 92, 66 },
+    { "tomato3", 205, 79, 57 },
+    { "tomato4", 139, 54, 38 },
+    { "turquoise", 64, 224, 208 },
+    { "turquoise1", 0, 245, 255 },
+    { "turquoise2", 0, 229, 238 },
+    { "turquoise3", 0, 197, 205 },
+    { "turquoise4", 0, 134, 139 },
+    { "violet", 238, 130, 238 },
+    { "violet red", 208, 32, 144 },
+    { "VioletRed", 208, 32, 144 },
+    { "VioletRed1", 255, 62, 150 },
+    { "VioletRed2", 238, 58, 140 },
+    { "VioletRed3", 205, 50, 120 },
+    { "VioletRed4", 139, 34, 82 },
+    { "wheat", 245, 222, 179 },
+    { "wheat1", 255, 231, 186 },
+    { "wheat2", 238, 216, 174 },
+    { "wheat3", 205, 186, 150 },
+    { "wheat4", 139, 126, 102 },
+    { "white", 255, 255, 255 },
+    { "white smoke", 245, 245, 245 },
+    { "WhiteSmoke", 245, 245, 245 },
+    { "yellow", 255, 255, 0 },
+    { "yellow green", 154, 205, 50 },
+    { "yellow1", 255, 255, 0 },
+    { "yellow2", 238, 238, 0 },
+    { "yellow3", 205, 205, 0 },
+    { "yellow4", 139, 139, 0 },
+    { "YellowGreen", 154, 205, 50 }
+};
+#define numXColors (sizeof (xColors) / sizeof (*xColors))
+/*
+ *----------------------------------------------------------------------
+ *
+ * FindColor --
+ *
+ *     This routine finds the color entry that corresponds to the
+ *     specified color.
+ *
+ * Results:
+ *     Returns non-zero on success.  The RGB values of the XColor
+ *     will be initialized to the proper values on success.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+compare_xcolor_entries (const void *a, const void *b)
+{
+  return strcasecmp ((const char *) a, ((const XColorEntry *) b)->name);
+}
+
+static int
+FindColor(const char *name,
+         GdkColor   *colorPtr)
+{
+  XColorEntry *found;
+
+  found = bsearch (name, xColors, numXColors, sizeof (XColorEntry),
+                  compare_xcolor_entries);
+  if (found == NULL)
+    return 0;
+  
+  colorPtr->red = (found->red * 65535) / 255;
+  colorPtr->green = (found->green * 65535) / 255;
+  colorPtr->blue = (found->blue * 65535) / 255;
+  return 1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * parse_color --
+ *
+ *     Partial implementation of X color name parsing interface.
+ *
+ * Results:
+ *     Returns non-zero on success.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+gboolean
+parse_color(Colormap    map,
+           const char *spec,
+           GdkColor   *colorPtr)
+{
+    if (spec[0] == '#') {
+       char fmt[16];
+       int i, red, green, blue;
+
+       if ((i = strlen(spec+1))%3) {
+           return 0;
+       }
+       i /= 3;
+
+       sprintf(fmt, "%%%dx%%%dx%%%dx", i, i, i);
+       if (sscanf(spec+1, fmt, &red, &green, &blue) != 3) {
+           return 0;
+       }
+       if (i == 4)
+         {
+           colorPtr->red = red;
+           colorPtr->green = green;
+           colorPtr->blue = blue;
+         }
+       else if (i == 1)
+         {
+           colorPtr->red = (red * 65535) / 15;
+           colorPtr->green = (green * 65535) / 15;
+           colorPtr->blue = (blue * 65535) / 15;
+         }
+       else if (i == 2)
+         {
+           colorPtr->red = (red * 65535) / 255;
+           colorPtr->green = (green * 65535) / 255;
+           colorPtr->blue = (blue * 65535) / 255;
+         }
+       else /* if (i == 3) */
+         {
+           colorPtr->red = (red * 65535) / 4095;
+           colorPtr->green = (green * 65535) / 4095;
+           colorPtr->blue = (blue * 65535) / 4095;
+         }
+    } else {
+       if (!FindColor(spec, colorPtr)) {
+           return 0;
+       }
+    }
+    return 1;
+}
+
+/* End of code from Tk8.0 */
+
+static Colormap
+DefaultColormap ()
+{
+  static Colormap colormap;
+  gint i;
+
+  if (colormap)
+    return colormap;
+
+  colormap = create_colormap ( NULL, NULL, AllocNone);
+  return colormap;
+}
+
+\f
+GdkColormap*
+gdk_colormap_new (GdkVisual *visual,
+                 gint       private_cmap)
+{
+  GdkColormap *colormap;
+  GdkColormapPrivate *private;
+  Visual *xvisual;
+  int size;
+  unsigned int i;
+
+  g_return_val_if_fail (visual != NULL, NULL);
+
+  private = g_new (GdkColormapPrivate, 1);
+  colormap = (GdkColormap*) private;
+
+  private->visual = visual;
+  private->ref_count = 1;
+
+  private->hash = NULL;
+  private->last_sync_time = 0;
+  private->info = NULL;
+  
+  xvisual = ((GdkVisualPrivate*) visual)->xvisual;
+
+  colormap->size = visual->colormap_size;
+  colormap->colors = g_new (GdkColor, colormap->size);
+
+  switch (visual->type)
+    {
+    case GDK_VISUAL_GRAYSCALE:
+    case GDK_VISUAL_PSEUDO_COLOR:
+      private->info = g_new0 (GdkColorInfo, colormap->size);
+      colormap->colors = g_new (GdkColor, colormap->size);
+      
+      private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
+                                       (GCompareFunc) gdk_color_equal);
+      
+      private->private_val = private_cmap;
+      private->xcolormap = create_colormap (gdk_root_window, xvisual,
+                                           (private_cmap) ? (AllocAll) : (AllocNone));
+
+      if (private_cmap)
+       {
+         PALETTEENTRY pal[256];
+         guint npal;
+
+         npal = GetPaletteEntries (private->xcolormap->palette, 0, colormap->size, pal);
+         for (i = 0; i < colormap->size; i++)
+           {
+             colormap->colors[i].pixel = i;
+             if (i >= npal)
+               {
+                 colormap->colors[i].red =
+                   colormap->colors[i].green =
+                   colormap->colors[i].blue = 0;
+               }
+             else
+               {
+                 colormap->colors[i].red = (pal[i].peRed * 65535) / 255;
+                 colormap->colors[i].green = (pal[i].peGreen * 65525) / 255;
+                 colormap->colors[i].blue = (pal[i].peBlue * 65535) / 255;
+               }
+           }
+         gdk_colormap_change (colormap, colormap->size);
+       }
+      break;
+
+    case GDK_VISUAL_STATIC_GRAY:
+    case GDK_VISUAL_STATIC_COLOR:
+    case GDK_VISUAL_TRUE_COLOR:
+      private->private_val = FALSE;
+      private->xcolormap = create_colormap (gdk_root_window,
+                                           xvisual, AllocNone);
+      break;
+    }
+
+  gdk_colormap_add (colormap);
+
+  return colormap;
+}
+
+static void
+gdk_colormap_real_destroy (GdkColormap *colormap)
+{
+  GdkColormapPrivate *private = (GdkColormapPrivate*) colormap;
+
+  g_return_if_fail (colormap != NULL);
+  g_return_if_fail (private->ref_count == 0);
+
+  gdk_colormap_remove (colormap);
+  XFreeColormap (private->xcolormap);
+
+  if (private->hash)
+    g_hash_table_destroy (private->hash);
+  
+  g_free (private->info);
+  g_free (colormap->colors);
+  g_free (colormap);
+}
+
+GdkColormap*
+gdk_colormap_ref (GdkColormap *cmap)
+{
+  GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
+
+  g_return_val_if_fail (cmap != NULL, NULL);
+
+  private->ref_count += 1;
+  return cmap;
+}
+
+void
+gdk_colormap_unref (GdkColormap *cmap)
+{
+  GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
+
+  g_return_if_fail (cmap != NULL);
+  g_return_if_fail (private->ref_count > 0);
+
+  private->ref_count -= 1;
+  if (private->ref_count == 0)
+    gdk_colormap_real_destroy (cmap);
+}
+
+#define MIN_SYNC_TIME 2
+
+GdkVisual *
+gdk_colormap_get_visual (GdkColormap *colormap)
+{
+  GdkColormapPrivate *private;
+
+  g_return_val_if_fail (colormap != NULL, NULL);
+  
+  private = (GdkColormapPrivate *)colormap;
+
+  return private->visual;
+}
+     
+void
+gdk_colormap_sync (GdkColormap *colormap,
+                  gboolean     force)
+{
+  time_t current_time;
+  GdkColormapPrivate *private = (GdkColormapPrivate *)colormap;
+  XColor *xpalette;
+  gint nlookup;
+  gint i;
+  
+  g_return_if_fail (colormap != NULL);
+
+  current_time = time (NULL);
+  if (!force && ((current_time - private->last_sync_time) < MIN_SYNC_TIME))
+    return;
+
+  private->last_sync_time = current_time;
+
+  nlookup = 0;
+  xpalette = g_new (XColor, colormap->size);
+  
+  nlookup = GetPaletteEntries (private->xcolormap->palette,
+                              0, colormap->size, xpalette);
+  
+  for (i = 0; i < nlookup; i++)
+    {
+      colormap->colors[i].pixel = i;
+      colormap->colors[i].red = (xpalette[i].peRed * 65535) / 255;
+      colormap->colors[i].green = (xpalette[i].peGreen * 65535) / 255;
+      colormap->colors[i].blue = (xpalette[i].peBlue * 65535) / 255;
+    }
+
+  g_free (xpalette);
+}
+                  
+
+GdkColormap*
+gdk_colormap_get_system (void)
+{
+  static GdkColormap *colormap = NULL;
+  GdkColormapPrivate *private;
+  gint i;
+
+  if (!colormap)
+    {
+      private = g_new (GdkColormapPrivate, 1);
+      colormap = (GdkColormap*) private;
+
+      private->xcolormap = DefaultColormap ();
+      private->visual = gdk_visual_get_system ();
+      private->private_val = FALSE;
+      private->ref_count = 1;
+
+      private->hash = NULL;
+      private->last_sync_time = 0;
+      private->info = NULL;
+
+      colormap->colors = NULL;
+      colormap->size = private->visual->colormap_size;
+
+      if ((private->visual->type == GDK_VISUAL_GRAYSCALE) ||
+         (private->visual->type == GDK_VISUAL_PSEUDO_COLOR))
+       {
+         private->info = g_new0 (GdkColorInfo, colormap->size);
+         colormap->colors = g_new (GdkColor, colormap->size);
+         
+         private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
+                                           (GCompareFunc) gdk_color_equal);
+
+         gdk_colormap_sync (colormap, TRUE);
+       }
+      gdk_colormap_add (colormap);
+    }
+
+  return colormap;
+}
+
+gint
+gdk_colormap_get_system_size (void)
+{
+  gint bitspixel;
+  
+  bitspixel = GetDeviceCaps (gdk_DC, BITSPIXEL);
+
+  if (bitspixel == 1)
+    return 2;
+  else if (bitspixel == 4)
+    return 16;
+  else if (bitspixel == 8)
+    return 256;
+  else if (bitspixel == 12)
+    return 32;
+  else if (bitspixel == 16)
+    return 64;
+  else /* if (bitspixel >= 24) */
+    return 256;
+}
+
+void
+gdk_colormap_change (GdkColormap *colormap,
+                    gint         ncolors)
+{
+  GdkColormapPrivate *private;
+  GdkVisual *visual;
+  XColor *palette;
+  gint shift;
+  int max_colors;
+  int size;
+  int i;
+
+  g_return_if_fail (colormap != NULL);
+
+  palette = g_new (XColor, ncolors);
+
+  private = (GdkColormapPrivate*) colormap;
+  switch (private->visual->type)
+    {
+    case GDK_VISUAL_GRAYSCALE:
+    case GDK_VISUAL_PSEUDO_COLOR:
+      for (i = 0; i < ncolors; i++)
+       {
+         palette[i].peRed = (colormap->colors[i].red >> 8);
+         palette[i].peGreen = (colormap->colors[i].green >> 8);
+         palette[i].peBlue = (colormap->colors[i].blue >> 8);
+         palette[i].peFlags = 0;
+       }
+
+      if (SetPaletteEntries (private->xcolormap->palette,
+                            0, ncolors, palette) == 0)
+       g_warning ("gdk_colormap_change: SetPaletteEntries failed");
+      private->xcolormap->stale = TRUE;
+      break;
+
+    default:
+      break;
+    }
+
+  g_free (palette);
+}
+
+void
+gdk_colors_store (GdkColormap   *colormap,
+                 GdkColor      *colors,
+                 gint           ncolors)
+{
+  gint i;
+
+  for (i = 0; i < ncolors; i++)
+    {
+      colormap->colors[i].pixel = colors[i].pixel;
+      colormap->colors[i].red = colors[i].red;
+      colormap->colors[i].green = colors[i].green;
+      colormap->colors[i].blue = colors[i].blue;
+    }
+
+  gdk_colormap_change (colormap, ncolors);
+}
+
+gboolean
+gdk_colors_alloc (GdkColormap   *colormap,
+                 gint           contiguous,
+                 gulong        *planes,
+                 gint           nplanes,
+                 gulong        *pixels,
+                 gint           npixels)
+{
+  GdkColormapPrivate *private;
+  gint return_val;
+  gint i;
+
+  g_return_val_if_fail (colormap != NULL, 0);
+
+  private = (GdkColormapPrivate*) colormap;
+
+  return_val = alloc_color_cells (private->xcolormap, contiguous,
+                                 planes, nplanes, pixels, npixels);
+
+  if (return_val)
+    {
+      for (i=0; i<npixels; i++)
+       {
+         private->info[pixels[i]].ref_count++;
+         private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE;
+       }
+    }
+
+  return return_val;
+}
+
+/* This is almost identical to gdk_colormap_free_colors.
+ * Keep them in sync!
+ */
+void
+gdk_colors_free (GdkColormap *colormap,
+                gulong      *in_pixels,
+                gint         in_npixels,
+                gulong       planes)
+{
+  GdkColormapPrivate *private;
+  gulong *pixels;
+  gint npixels = 0;
+  gint i;
+
+  g_return_if_fail (colormap != NULL);
+  g_return_if_fail (in_pixels != NULL);
+
+  private = (GdkColormapPrivate*) colormap;
+
+  if ((private->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
+      (private->visual->type != GDK_VISUAL_GRAYSCALE))
+    return;
+  
+  pixels = g_new (gulong, in_npixels);
+
+  for (i=0; i<in_npixels; i++)
+    {
+      gulong pixel = in_pixels[i];
+      
+      if (private->info[pixel].ref_count)
+       {
+         private->info[pixel].ref_count--;
+
+         if (private->info[pixel].ref_count == 0)
+           {
+             pixels[npixels++] = pixel;
+             if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
+               g_hash_table_remove (private->hash, &colormap->colors[in_pixels[i]]);
+             private->info[pixel].flags = 0;
+           }
+       }
+    }
+
+
+  if (npixels)
+    XFreeColors (private->xcolormap, pixels, npixels, planes);
+
+  g_free (pixels);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_color_copy
+ *
+ *   Copy a color structure into new storage.
+ *
+ * Arguments:
+ *   "color" is the color struct to copy.
+ *
+ * Results:
+ *   A new color structure.  Free it with gdk_color_free.
+ *
+ *--------------------------------------------------------------
+ */
+
+static GMemChunk *color_chunk;
+
+GdkColor*
+gdk_color_copy (GdkColor *color)
+{
+  GdkColor *new_color;
+  
+  g_return_val_if_fail (color != NULL, NULL);
+
+  if (color_chunk == NULL)
+    color_chunk = g_mem_chunk_new ("colors",
+                                  sizeof (GdkColor),
+                                  4096,
+                                  G_ALLOC_AND_FREE);
+
+  new_color = g_chunk_new (GdkColor, color_chunk);
+  *new_color = *color;
+  return new_color;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_color_free
+ *
+ *   Free a color structure obtained from gdk_color_copy.  Do not use
+ *   with other color structures.
+ *
+ * Arguments:
+ *   "color" is the color struct to free.
+ *
+ *-------------------------------------------------------------- */
+
+void
+gdk_color_free (GdkColor *color)
+{
+  g_assert (color_chunk != NULL);
+  g_return_if_fail (color != NULL);
+
+  g_mem_chunk_free (color_chunk, color);
+}
+
+gint
+gdk_color_white (GdkColormap *colormap,
+                GdkColor    *color)
+{
+  gint return_val;
+
+  g_return_val_if_fail (colormap != NULL, FALSE);
+
+  if (color)
+    {
+      color->red = 65535;
+      color->green = 65535;
+      color->blue = 65535;
+
+      return_val = gdk_color_alloc (colormap, color);
+    }
+  else
+    return_val = FALSE;
+
+  return return_val;
+}
+
+gint
+gdk_color_black (GdkColormap *colormap,
+                GdkColor    *color)
+{
+  gint return_val;
+
+  g_return_val_if_fail (colormap != NULL, FALSE);
+
+  if (color)
+    {
+      color->red = 0;
+      color->green = 0;
+      color->blue = 0;
+
+      return_val = gdk_color_alloc (colormap, color);
+    }
+  else
+    return_val = FALSE;
+
+  return return_val;
+}
+
+gboolean
+gdk_color_parse (const gchar *spec,
+                GdkColor *color)
+{
+  Colormap xcolormap;
+  XColor xcolor;
+  gboolean return_val;
+
+  g_return_val_if_fail (spec != NULL, FALSE);
+  g_return_val_if_fail (color != NULL, FALSE);
+
+  xcolormap = DefaultColormap ();
+
+  if (parse_color (xcolormap, spec, color))
+    return_val = TRUE;
+  else
+    return_val = FALSE;
+
+  return return_val;
+}
+
+/********************
+ * Color allocation *
+ ********************/
+
+/* Try to allocate a single color using alloc_color. If it succeeds,
+ * cache the result in our colormap, and store in ret.
+ */
+static gboolean 
+gdk_colormap_alloc1 (GdkColormap *colormap,
+                    GdkColor    *color,
+                    GdkColor    *ret)
+{
+  GdkColormapPrivate *private;
+  XColor xcolor;
+
+  private = (GdkColormapPrivate*) colormap;
+
+  xcolor.peRed = color->red >> 8;
+  xcolor.peGreen = color->green >> 8;
+  xcolor.peBlue = color->blue >> 8;
+
+  if (alloc_color (private->xcolormap, &xcolor, &ret->pixel))
+    {
+      ret->red = (xcolor.peRed * 65535) / 255;
+      ret->green = (xcolor.peGreen * 65535) / 255;;
+      ret->blue = (xcolor.peBlue * 65535) / 255;
+      
+      if ((guint) ret->pixel < colormap->size)
+       {
+         if (private->info[ret->pixel].ref_count) /* got a duplicate */
+           {
+             /* XXX */
+           }
+         else
+           {
+             colormap->colors[ret->pixel] = *color;
+             private->info[ret->pixel].ref_count = 1;
+
+             g_hash_table_insert (private->hash,
+                                  &colormap->colors[ret->pixel],
+                                  &colormap->colors[ret->pixel]);
+           }
+       }
+      return TRUE;
+    }
+  else
+    {
+      return FALSE;
+    }
+}
+
+static gint
+gdk_colormap_alloc_colors_writeable (GdkColormap *colormap,
+                                    GdkColor    *colors,
+                                    gint         ncolors,
+                                    gboolean     writeable,
+                                    gboolean     best_match,
+                                    gboolean    *success)
+{
+  GdkColormapPrivate *private;
+  gulong *pixels;
+  Status status;
+  gint i, index;
+
+  private = (GdkColormapPrivate*) colormap;
+
+  if (private->private_val)
+    {
+      index = 0;
+      for (i=0; i<ncolors; i++)
+       {
+         while ((index < colormap->size) && (private->info[index].ref_count != 0))
+           index++;
+         
+         if (index < colormap->size)
+           {
+             colors[i].pixel = index;
+             success[i] = TRUE;
+             private->info[index].ref_count++;
+             private->info[i].flags |= GDK_COLOR_WRITEABLE;
+           }
+         else
+           break;
+       }
+      return i;
+    }
+  else
+    {
+      pixels = g_new (gulong, ncolors);
+
+      /* Allocation of a writeable color cells */
+      status =  alloc_color_cells (private->xcolormap, FALSE, NULL,
+                                  0, pixels, ncolors);
+      if (status)
+       {
+         for (i=0; i<ncolors; i++)
+           {
+             colors[i].pixel = pixels[i];
+             private->info[pixels[i]].ref_count++;
+             private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE;
+           }
+       }
+      
+      g_free (pixels);
+
+      return status ? ncolors : 0; 
+    }
+}
+
+static gint
+gdk_colormap_alloc_colors_private (GdkColormap *colormap,
+                                  GdkColor    *colors,
+                                  gint         ncolors,
+                                  gboolean     writeable,
+                                  gboolean     best_match,
+                                  gboolean    *success)
+{
+  GdkColormapPrivate *private;
+  gint i, index;
+  XColor *store = g_new (XColor, ncolors);
+  gint nstore = 0;
+  gint nremaining = 0;
+  
+  private = (GdkColormapPrivate*) colormap;
+  index = -1;
+
+  /* First, store the colors we have room for */
+
+  index = 0;
+  for (i=0; i<ncolors; i++)
+    {
+      if (!success[i])
+       {
+         while ((index < colormap->size) && (private->info[index].ref_count != 0))
+           index++;
+
+         if (index < colormap->size)
+           {
+             store[nstore].peRed = colors[i].red >> 8;
+             store[nstore].peBlue = colors[i].blue >> 8;
+             store[nstore].peGreen = colors[i].green >> 8;
+             nstore++;
+
+             success[i] = TRUE;
+
+             colors[i].pixel = index;
+             private->info[index].ref_count++;
+           }
+         else
+           nremaining++;
+       }
+    }
+  
+  if (SetPaletteEntries (private->xcolormap->palette,
+                        0, nstore, store) == 0)
+    g_warning ("gdk_colormap_alloc_colors_private: SetPaletteEntries failed");
+  private->xcolormap->stale = TRUE;
+
+  g_free (store);
+
+  if (nremaining > 0 && best_match)
+    {
+      /* Get best matches for remaining colors */
+
+      gchar *available = g_new (gchar, colormap->size);
+      for (i = 0; i < colormap->size; i++)
+       available[i] = TRUE;
+
+      for (i=0; i<ncolors; i++)
+       {
+         if (!success[i])
+           {
+             index = gdk_colormap_match_color (colormap, 
+                                               &colors[i], 
+                                               available);
+             if (index != -1)
+               {
+                 colors[i] = colormap->colors[index];
+                 private->info[index].ref_count++;
+                 success[i] = TRUE;
+                 nremaining--;
+               }
+           }
+       }
+      g_free (available);
+    }
+
+  return (ncolors - nremaining);
+}
+
+static gint
+gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
+                                 GdkColor    *colors,
+                                 gint         ncolors,
+                                 gboolean     writeable,
+                                 gboolean     best_match,
+                                 gboolean    *success)
+{
+  GdkColormapPrivate *private;
+  gint i, index;
+  gint nremaining = 0;
+  gint nfailed = 0;
+
+  private = (GdkColormapPrivate*) colormap;
+  index = -1;
+
+  for (i=0; i<ncolors; i++)
+    {
+      if (!success[i])
+       {
+         if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
+           success[i] = TRUE;
+         else
+           nremaining++;
+       }
+    }
+
+
+  if (nremaining > 0 && best_match)
+    {
+      gchar *available = g_new (gchar, colormap->size);
+      for (i = 0; i < colormap->size; i++)
+       available[i] = ((private->info[i].ref_count == 0) ||
+                       !(private->info[i].flags && GDK_COLOR_WRITEABLE));
+      gdk_colormap_sync (colormap, FALSE);
+      
+      while (nremaining > 0)
+       {
+         for (i=0; i<ncolors; i++)
+           {
+             if (!success[i])
+               {
+                 index = gdk_colormap_match_color (colormap, &colors[i], available);
+                 if (index != -1)
+                   {
+                     if (private->info[index].ref_count)
+                       {
+                         private->info[index].ref_count++;
+                         colors[i] = colormap->colors[index];
+                         success[i] = TRUE;
+                         nremaining--;
+                       }
+                     else
+                       {
+                         if (gdk_colormap_alloc1 (colormap, 
+                                                  &colormap->colors[index],
+                                                  &colors[i]))
+                           {
+                             success[i] = TRUE;
+                             nremaining--;
+                             break;
+                           }
+                         else
+                           {
+                             available[index] = FALSE;
+                           }
+                       }
+                   }
+                 else
+                   {
+                     nfailed++;
+                     nremaining--;
+                     success[i] = 2; /* flag as permanent failure */
+                   }
+               }
+           }
+       }
+      g_free (available);
+    }
+
+  /* Change back the values we flagged as permanent failures */
+  if (nfailed > 0)
+    {
+      for (i=0; i<ncolors; i++)
+       if (success[i] == 2)
+         success[i] = FALSE;
+      nremaining = nfailed;
+    }
+  
+  return (ncolors - nremaining);
+}
+
+static gint
+gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
+                                      GdkColor    *colors,
+                                      gint         ncolors,
+                                      gboolean     writeable,
+                                      gboolean     best_match,
+                                      gboolean    *success)
+{
+  GdkColormapPrivate *private;
+  GdkColor *lookup_color;
+  gint i;
+  gint nremaining = 0;
+
+  private = (GdkColormapPrivate*) colormap;
+
+  /* Check for an exact match among previously allocated colors */
+
+  for (i=0; i<ncolors; i++)
+    {
+      if (!success[i])
+       {
+         lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
+         if (lookup_color)
+           {
+             private->info[lookup_color->pixel].ref_count++;
+             colors[i].pixel = lookup_color->pixel;
+             success[i] = TRUE;
+           }
+         else
+           nremaining++;
+       }
+    }
+
+  /* If that failed, we try to allocate a new color, or approxmiate
+   * with what we can get if best_match is TRUE.
+   */
+  if (nremaining > 0)
+    {
+      if (private->private_val)
+       return gdk_colormap_alloc_colors_private (colormap, colors, ncolors, writeable, best_match, success);
+      else
+       return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
+    }
+  else
+    return 0;
+}
+
+gint
+gdk_colormap_alloc_colors (GdkColormap *colormap,
+                          GdkColor    *colors,
+                          gint         ncolors,
+                          gboolean     writeable,
+                          gboolean     best_match,
+                          gboolean    *success)
+{
+  GdkColormapPrivate *private;
+  GdkVisual *visual;
+  gint i;
+  gint nremaining = 0;
+  XColor xcolor;
+
+  g_return_val_if_fail (colormap != NULL, FALSE);
+  g_return_val_if_fail (colors != NULL, FALSE);
+
+  private = (GdkColormapPrivate*) colormap;
+
+  for (i=0; i<ncolors; i++)
+    {
+      success[i] = FALSE;
+    }
+
+  switch (private->visual->type)
+    {
+    case GDK_VISUAL_PSEUDO_COLOR:
+    case GDK_VISUAL_GRAYSCALE:
+      if (writeable)
+       return gdk_colormap_alloc_colors_writeable (colormap, colors, ncolors,
+                                                   writeable, best_match, success);
+      else
+       return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors,
+                                                   writeable, best_match, success);
+      break;
+
+    case GDK_VISUAL_TRUE_COLOR:
+      visual = private->visual;
+
+      for (i=0; i<ncolors; i++)
+       {
+         colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) +
+                            ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) +
+                            ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift));
+         success[i] = TRUE;
+       }
+      break;
+
+    case GDK_VISUAL_STATIC_GRAY:
+    case GDK_VISUAL_STATIC_COLOR:
+      for (i=0; i<ncolors; i++)
+       {
+         xcolor.peRed = colors[i].red >> 8;
+         xcolor.peGreen = colors[i].green >> 8;
+         xcolor.peBlue = colors[i].blue >> 8;
+         if (alloc_color (private->xcolormap, &xcolor, &colors[i].pixel))
+           success[i] = TRUE;
+         else
+           nremaining++;
+       }
+      break;
+    }
+  return nremaining;
+}
+
+gboolean
+gdk_colormap_alloc_color (GdkColormap *colormap,
+                         GdkColor    *color,
+                         gboolean     writeable,
+                         gboolean     best_match)
+{
+  gboolean success;
+
+  GDK_NOTE (MISC, g_print ("gdk_colormap_alloc_color: (%.04x,%.04x,%.04x)",
+                          color->red, color->green, color->blue));
+
+  gdk_colormap_alloc_colors (colormap, color, 1, writeable, best_match,
+                            &success);
+  GDK_NOTE (MISC, g_print (" -> %.08x\n", color->pixel));
+
+  return success;
+}
+
+/* This is almost identical to gdk_colors_free.
+ * Keep them in sync!
+ */
+void
+gdk_colormap_free_colors (GdkColormap *colormap,
+                         GdkColor    *colors,
+                         gint         ncolors)
+{
+  GdkColormapPrivate *private;
+  gulong *pixels;
+  gint npixels = 0;
+  gint i;
+
+  g_return_if_fail (colormap != NULL);
+  g_return_if_fail (colors != NULL);
+
+  private = (GdkColormapPrivate*) colormap;
+
+  if ((private->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
+      (private->visual->type != GDK_VISUAL_GRAYSCALE))
+    return;
+
+  pixels = g_new (gulong, ncolors);
+
+  for (i=0; i<ncolors; i++)
+    {
+      gulong pixel = colors[i].pixel;
+      
+      if (private->info[pixel].ref_count)
+       {
+         private->info[pixel].ref_count--;
+
+         if (private->info[pixel].ref_count == 0)
+           {
+             pixels[npixels++] = pixel;
+             if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
+               g_hash_table_remove (private->hash, &colors[i]);
+             private->info[pixel].flags = 0;
+           }
+       }
+    }
+  if (npixels)
+    XFreeColors (private->xcolormap, pixels, npixels, 0);
+  g_free (pixels);
+}
+
+gboolean
+gdk_color_alloc (GdkColormap *colormap,
+                GdkColor    *color)
+{
+  gboolean success;
+
+  GDK_NOTE (MISC, g_print ("gdk_color_alloc: (%.04x,%.04x,%.04x)",
+                          color->red, color->green, color->blue));
+
+  gdk_colormap_alloc_colors (colormap, color, 1, FALSE, TRUE, &success);
+
+  GDK_NOTE (MISC, g_print (" -> %.08x\n", color->pixel));
+
+  return success;
+}
+
+gboolean
+gdk_color_change (GdkColormap *colormap,
+                 GdkColor    *color)
+{
+  GdkColormapPrivate *private;
+  XColor xcolor;
+
+  g_return_val_if_fail (colormap != NULL, FALSE);
+  g_return_val_if_fail (color != NULL, FALSE);
+
+  private = (GdkColormapPrivate*) colormap;
+
+  xcolor.peRed = color->red >> 8;
+  xcolor.peGreen = color->green >> 8;
+  xcolor.peBlue = color->blue >> 8;
+
+  if (SetPaletteEntries (private->xcolormap->palette,
+                        color->pixel, 1, &xcolor) == 0)
+    g_warning ("gdk_color_change: SetPaletteEntries failed");
+  private->xcolormap->stale = TRUE;
+
+  return TRUE;
+}
+
+guint
+gdk_color_hash (const GdkColor *colora)
+{
+  return ((colora->red) +
+         (colora->green << 11) +
+         (colora->blue << 22) +
+         (colora->blue >> 6));
+}
+
+gint
+gdk_color_equal (const GdkColor *colora,
+                const GdkColor *colorb)
+{
+  g_return_val_if_fail (colora != NULL, FALSE);
+  g_return_val_if_fail (colorb != NULL, FALSE);
+
+  return ((colora->red == colorb->red) &&
+         (colora->green == colorb->green) &&
+         (colora->blue == colorb->blue));
+}
+
+static gint
+gdk_colormap_match_color (GdkColormap *cmap,
+                         GdkColor    *color,
+                         const gchar *available)
+{
+  GdkColor *colors;
+  guint sum, max;
+  gint rdiff, gdiff, bdiff;
+  gint i, index;
+
+  g_return_val_if_fail (cmap != NULL, 0);
+  g_return_val_if_fail (color != NULL, 0);
+
+  colors = cmap->colors;
+  max = 3 * (65536);
+  index = -1;
+
+  for (i = 0; i < cmap->size; i++)
+    {
+      if ((!available) || (available && available[i]))
+       {
+         rdiff = (color->red - colors[i].red);
+         gdiff = (color->green - colors[i].green);
+         bdiff = (color->blue - colors[i].blue);
+
+         sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
+
+         if (sum < max)
+           {
+             index = i;
+             max = sum;
+           }
+       }
+    }
+
+  return index;
+}
+
+GdkColormap*
+gdk_colormap_lookup (Colormap xcolormap)
+{
+  GdkColormap *cmap;
+
+  if (!colormap_hash)
+    return NULL;
+
+  cmap = g_hash_table_lookup (colormap_hash, &xcolormap);
+  return cmap;
+}
+
+static void
+gdk_colormap_add (GdkColormap *cmap)
+{
+  GdkColormapPrivate *private;
+
+  if (!colormap_hash)
+    colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
+                                     (GCompareFunc) gdk_colormap_cmp);
+
+  private = (GdkColormapPrivate*) cmap;
+
+  g_hash_table_insert (colormap_hash, &private->xcolormap, cmap);
+}
+
+static void
+gdk_colormap_remove (GdkColormap *cmap)
+{
+  GdkColormapPrivate *private;
+
+  if (!colormap_hash)
+    colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
+                                     (GCompareFunc) gdk_colormap_cmp);
+
+  private = (GdkColormapPrivate*) cmap;
+
+  g_hash_table_remove (colormap_hash, &private->xcolormap);
+}
+
+static guint
+gdk_colormap_hash (Colormap *cmap)
+{
+  return (guint) *cmap;
+}
+
+static gint
+gdk_colormap_cmp (Colormap *a,
+                 Colormap *b)
+{
+  return (*a == *b);
+}
+
+char *
+gdk_color_to_string (GdkColor *color)
+{
+  static char buf[100];
+
+  sprintf (buf, "(%.04x,%.04x,%.04x): %.06x",
+          color->red, color->green, color->blue, color->pixel);
+
+  return buf;
+}
diff --git a/gdk/win32/gdkcolor.c b/gdk/win32/gdkcolor.c
new file mode 100644 (file)
index 0000000..4b81f24
--- /dev/null
@@ -0,0 +1,2443 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkx.h"
+
+#ifdef _MSC_VER
+#define strcasecmp stricmp
+#endif
+
+static gint  gdk_colormap_match_color (GdkColormap *cmap,
+                                      GdkColor    *color,
+                                      const gchar *available);
+static void  gdk_colormap_add         (GdkColormap *cmap);
+static void  gdk_colormap_remove      (GdkColormap *cmap);
+static guint gdk_colormap_hash        (Colormap    *cmap);
+static gint  gdk_colormap_cmp         (Colormap    *a,
+                                      Colormap    *b);
+static void gdk_colormap_real_destroy (GdkColormap *colormap);
+
+static GHashTable *colormap_hash = NULL;
+
+static Status
+alloc_color_cells(Colormap      colormap,
+                 gboolean      contig,
+                 unsigned long plane_masks_return[],
+                 unsigned int  nplanes,
+                 unsigned long pixels_return[],
+                 unsigned int  npixels)
+{
+  unsigned int i, nfree, iret;
+
+  nfree = 0;
+  for (i = 0; i < colormap->size && nfree < npixels; i++)
+    if (!colormap->in_use[i])
+      nfree++;
+
+  if (colormap->size + npixels - nfree > colormap->sizepalette)
+    {
+      g_warning ("alloc_color_cells: too large palette: %d",
+                colormap->size + npixels);
+      return FALSE;
+    }
+
+  iret = 0;
+  for (i = 0; i < colormap->size && iret < npixels; i++)
+    if (!colormap->in_use[i])
+      {
+       colormap->in_use[i] = TRUE;
+       pixels_return[iret] = i;
+       iret++;
+      }
+
+  if (nfree < npixels)
+    {
+      int nmore = npixels - nfree;
+
+      /* I don't understand why, if the code below in #if 0 is
+        enabled, gdkrgb fails miserably. The palette doesn't get
+        realized correctly. There doesn't seem to be any harm done by
+        keeping this code out, either.  */
+#ifdef SOME_STRANGE_BUG
+      if (!ResizePalette (colormap->palette, colormap->size + nmore))
+       {
+         g_warning ("alloc_color_cells: ResizePalette to %d failed",
+                    colormap->size + nmore);
+         return FALSE;
+       }
+      g_print("alloc_color_cells: %#x to %d\n",
+             colormap->palette, colormap->size + nmore);
+#endif
+      for (i = colormap->size; i < colormap->size + nmore; i++)
+       {
+         pixels_return[iret] = i;
+         iret++;
+         colormap->in_use[i] = TRUE;
+       }
+#ifdef SOME_STRANGE_BUG
+      colormap->size += nmore;
+#endif
+    }
+  return TRUE;
+}
+
+/* The following functions are from Tk8.0, but heavily modified.
+   Here are tk's licensing terms. I hope these terms don't conflict
+   with the GNU Library General Public License? They shouldn't, as
+   they are looser that the GLPL, yes? */
+
+/*
+This software is copyrighted by the Regents of the University of
+California, Sun Microsystems, Inc., and other parties.  The following
+terms apply to all files associated with the software unless explicitly
+disclaimed in individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+GOVERNMENT USE: If you are acquiring this software on behalf of the
+U.S. government, the Government shall have only "Restricted Rights"
+in the software and related documentation as defined in the Federal 
+Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
+are acquiring the software on behalf of the Department of Defense, the
+software shall be classified as "Commercial Computer Software" and the
+Government shall have only "Restricted Rights" as defined in Clause
+252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
+authors grant the U.S. Government and others acting in its behalf
+permission to use and distribute the software in accordance with the
+terms specified in this license.
+*/
+/*
+ *----------------------------------------------------------------------
+ *
+ * XAllocColor --
+ *
+ *     Find the closest available color to the specified XColor.
+ *
+ * Results:
+ *     Updates the color argument and returns 1 on success.  Otherwise
+ *     returns 0.
+ *
+ * Side effects:
+ *     Allocates a new color in the palette.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+alloc_color(Colormap  colormap,
+           XColor   *color,
+           guint    *pixelp)
+{
+  PALETTEENTRY entry, closeEntry;
+  HDC hdc;
+  unsigned int i;
+    
+  entry = *color;
+  entry.peFlags = 0;
+
+  if (colormap->rc_palette)
+    {
+      COLORREF newPixel, closePixel;
+      UINT index;
+
+      /*
+       * Find the nearest existing palette entry.
+       */
+       
+      newPixel = RGB (entry.peRed, entry.peGreen, entry.peBlue);
+      index = GetNearestPaletteIndex (colormap->palette, newPixel);
+      GetPaletteEntries (colormap->palette, index, 1, &closeEntry);
+      closePixel = RGB (closeEntry.peRed, closeEntry.peGreen,
+                       closeEntry.peBlue);
+
+      if (newPixel != closePixel)
+       {
+         /* Not a perfect match. */
+         if (!colormap->in_use[index])
+           {
+             /* It was a free'd entry anyway, so we can use it, and
+                set it to the correct color. */
+             if (SetPaletteEntries (colormap->palette, index, 1, &entry) == 0)
+               g_warning ("alloc_color: SetPaletteEntries #1 failed");
+           }
+         else
+           {
+             /* The close entry found is in use, so search for a
+                unused slot. */
+                
+             for (i = 0; i < colormap->size; i++)
+               if (!colormap->in_use[i])
+                 {
+                   /* A free slot, use it. */
+                   if (SetPaletteEntries (colormap->palette,
+                                          index, 1, &entry) == 0)
+                     g_warning ("alloc_color: SetPaletteEntries #2 failed");
+                   index = i;
+                   break;
+                 }
+             if (i == colormap->size)
+               {
+                 /* No free slots found. If the palette isn't maximal
+                    yet, grow it. */
+                 if (colormap->size == colormap->sizepalette)
+                   {
+                     /* The palette is maximal, and no free slots available,
+                        so use the close entry, then, dammit. */
+                     *color = closeEntry;
+                   }
+                 else
+                   {
+                     /* There is room to grow the palette. */
+                     index = colormap->size;
+                     colormap->size++;
+                     if (!ResizePalette (colormap->palette, colormap->size))
+                       g_warning ("alloc_color: ResizePalette to %d failed",
+                                  colormap->size);
+                     if (SetPaletteEntries (colormap->palette, index, 1, &entry) == 0)
+                       g_warning ("alloc_color: SetPaletteEntries #3 failed");
+                   }
+               }
+           }
+         colormap->stale = TRUE;
+       }
+      else
+       {
+         /* We got a match, so use it. */
+       }
+
+      *pixelp = index;
+      colormap->in_use[index] = TRUE;
+#if 0
+      g_print("alloc_color from %#x: index %d for %02x %02x %02x\n",
+             colormap->palette, index,
+             entry.peRed, entry.peGreen, entry.peBlue);
+#endif
+    }
+  else
+    {
+      /*
+       * Determine what color will actually be used on non-colormap systems.
+       */
+      *pixelp = GetNearestColor (gdk_DC, RGB(entry.peRed, entry.peGreen, entry.peBlue));
+      
+      color->peRed = GetRValue (*pixelp);
+      color->peGreen = GetGValue (*pixelp);
+      color->peBlue = GetBValue (*pixelp);
+    }
+  
+  return 1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XFreeColors --
+ *
+ *     Deallocate a block of colors.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Removes entries for the current palette and compacts the
+ *     remaining set.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+XFreeColors(Colormap colormap,
+           gulong  *pixels,
+           gint     npixels,
+           gulong   planes)
+{
+  gint i;
+  PALETTEENTRY entries[256];
+
+  /*
+   * We don't have to do anything for non-palette devices.
+   */
+  
+  if (colormap->rc_palette)
+    {
+      int npal;
+      int lowestpixel = 256;
+      int highestpixel = -1;
+
+      npal = GetPaletteEntries (colormap->palette, 0, 256, entries);
+      for (i = 0; i < npixels; i++)
+       {
+         int pixel = pixels[i];
+
+         if (pixel < lowestpixel)
+           lowestpixel = pixel;
+         if (pixel > highestpixel)
+           highestpixel = pixel;
+
+         colormap->in_use[pixel] = FALSE;
+
+         entries[pixel] = entries[0];
+       }
+#if 0
+      if (SetPaletteEntries (colormap->palette, lowestpixel,
+                            highestpixel - lowestpixel + 1,
+                            entries + lowestpixel) == 0)
+       g_warning ("XFreeColors: SetPaletteEntries failed");
+#endif
+      colormap->stale = TRUE;
+#if 0
+      g_print("XFreeColors %#x lowestpixel = %d, highestpixel = %d\n",
+             colormap->palette, lowestpixel, highestpixel);
+#endif
+    }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XCreateColormap --
+ *
+ *     Allocate a new colormap.
+ *
+ * Results:
+ *     Returns a newly allocated colormap.
+ *
+ * Side effects:
+ *     Allocates an empty palette and color list.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Colormap
+create_colormap (HWND     w,
+                Visual  *visual,
+                int      alloc)
+{
+  char logPalBuf[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)];
+  LOGPALETTE *logPalettePtr;
+  PALETTEENTRY *entryPtr;
+  Colormap colormap;
+  guint i;
+  HPALETTE sysPal;
+  HDC hdc;
+
+  /* Should the alloc parameter do something? */
+
+
+  /* Allocate a starting palette with all of the reserved colors. */
+  
+  logPalettePtr = (LOGPALETTE *) logPalBuf;
+  logPalettePtr->palVersion = 0x300;
+  sysPal = (HPALETTE) GetStockObject (DEFAULT_PALETTE);
+  logPalettePtr->palNumEntries =
+    GetPaletteEntries (sysPal, 0, 256, logPalettePtr->palPalEntry);
+  
+  colormap = (Colormap) g_new (ColormapStruct, 1);
+  colormap->size = logPalettePtr->palNumEntries;
+  colormap->stale = TRUE;
+  colormap->palette = CreatePalette (logPalettePtr);
+  hdc = GetDC (NULL);
+  colormap->rc_palette = ((GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE) != 0);
+  if (colormap->rc_palette)
+    {
+      colormap->sizepalette = GetDeviceCaps (hdc, SIZEPALETTE);
+      colormap->in_use = g_new (gboolean, colormap->sizepalette);
+      /* Mark static colors in use. */
+      for (i = 0; i < logPalettePtr->palNumEntries; i++)
+       colormap->in_use[i] = TRUE;
+      /* Mark rest not in use */
+      for (i = logPalettePtr->palNumEntries; i < colormap->sizepalette; i++)
+       colormap->in_use[i] = FALSE;
+    }
+  ReleaseDC (NULL, hdc);
+
+  return colormap;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XFreeColormap --
+ *
+ *     Frees the resources associated with the given colormap.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Deletes the palette associated with the colormap.  Note that
+ *     the palette must not be selected into a device context when
+ *     this occurs.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+XFreeColormap(Colormap  colormap)
+{
+  if (!DeleteObject (colormap->palette))
+    {
+      g_error ("Unable to free colormap, palette is still selected.");
+    }
+  g_free (colormap);
+}
+
+typedef struct {
+    char *name;
+    unsigned char red;
+    unsigned char green;
+    unsigned char blue;
+} XColorEntry;
+
+static XColorEntry xColors[] = {
+    { "alice blue", 240, 248, 255 },
+    { "AliceBlue", 240, 248, 255 },
+    { "antique white", 250, 235, 215 },
+    { "AntiqueWhite", 250, 235, 215 },
+    { "AntiqueWhite1", 255, 239, 219 },
+    { "AntiqueWhite2", 238, 223, 204 },
+    { "AntiqueWhite3", 205, 192, 176 },
+    { "AntiqueWhite4", 139, 131, 120 },
+    { "aquamarine", 127, 255, 212 },
+    { "aquamarine1", 127, 255, 212 },
+    { "aquamarine2", 118, 238, 198 },
+    { "aquamarine3", 102, 205, 170 },
+    { "aquamarine4", 69, 139, 116 },
+    { "azure", 240, 255, 255 },
+    { "azure1", 240, 255, 255 },
+    { "azure2", 224, 238, 238 },
+    { "azure3", 193, 205, 205 },
+    { "azure4", 131, 139, 139 },
+    { "beige", 245, 245, 220 },
+    { "bisque", 255, 228, 196 },
+    { "bisque1", 255, 228, 196 },
+    { "bisque2", 238, 213, 183 },
+    { "bisque3", 205, 183, 158 },
+    { "bisque4", 139, 125, 107 },
+    { "black", 0, 0, 0 },
+    { "blanched almond", 255, 235, 205 },
+    { "BlanchedAlmond", 255, 235, 205 },
+    { "blue", 0, 0, 255 },
+    { "blue violet", 138, 43, 226 },
+    { "blue1", 0, 0, 255 },
+    { "blue2", 0, 0, 238 },
+    { "blue3", 0, 0, 205 },
+    { "blue4", 0, 0, 139 },
+    { "BlueViolet", 138, 43, 226 },
+    { "brown", 165, 42, 42 },
+    { "brown1", 255, 64, 64 },
+    { "brown2", 238, 59, 59 },
+    { "brown3", 205, 51, 51 },
+    { "brown4", 139, 35, 35 },
+    { "burlywood", 222, 184, 135 },
+    { "burlywood1", 255, 211, 155 },
+    { "burlywood2", 238, 197, 145 },
+    { "burlywood3", 205, 170, 125 },
+    { "burlywood4", 139, 115, 85 },
+    { "cadet blue", 95, 158, 160 },
+    { "CadetBlue", 95, 158, 160 },
+    { "CadetBlue1", 152, 245, 255 },
+    { "CadetBlue2", 142, 229, 238 },
+    { "CadetBlue3", 122, 197, 205 },
+    { "CadetBlue4", 83, 134, 139 },
+    { "chartreuse", 127, 255, 0 },
+    { "chartreuse1", 127, 255, 0 },
+    { "chartreuse2", 118, 238, 0 },
+    { "chartreuse3", 102, 205, 0 },
+    { "chartreuse4", 69, 139, 0 },
+    { "chocolate", 210, 105, 30 },
+    { "chocolate1", 255, 127, 36 },
+    { "chocolate2", 238, 118, 33 },
+    { "chocolate3", 205, 102, 29 },
+    { "chocolate4", 139, 69, 19 },
+    { "coral", 255, 127, 80 },
+    { "coral1", 255, 114, 86 },
+    { "coral2", 238, 106, 80 },
+    { "coral3", 205, 91, 69 },
+    { "coral4", 139, 62, 47 },
+    { "cornflower blue", 100, 149, 237 },
+    { "CornflowerBlue", 100, 149, 237 },
+    { "cornsilk", 255, 248, 220 },
+    { "cornsilk1", 255, 248, 220 },
+    { "cornsilk2", 238, 232, 205 },
+    { "cornsilk3", 205, 200, 177 },
+    { "cornsilk4", 139, 136, 120 },
+    { "cyan", 0, 255, 255 },
+    { "cyan1", 0, 255, 255 },
+    { "cyan2", 0, 238, 238 },
+    { "cyan3", 0, 205, 205 },
+    { "cyan4", 0, 139, 139 },
+    { "dark blue", 0, 0, 139 },
+    { "dark cyan", 0, 139, 139 },
+    { "dark goldenrod", 184, 134, 11 },
+    { "dark gray", 169, 169, 169 },
+    { "dark green", 0, 100, 0 },
+    { "dark grey", 169, 169, 169 },
+    { "dark khaki", 189, 183, 107 },
+    { "dark magenta", 139, 0, 139 },
+    { "dark olive green", 85, 107, 47 },
+    { "dark orange", 255, 140, 0 },
+    { "dark orchid", 153, 50, 204 },
+    { "dark red", 139, 0, 0 },
+    { "dark salmon", 233, 150, 122 },
+    { "dark sea green", 143, 188, 143 },
+    { "dark slate blue", 72, 61, 139 },
+    { "dark slate gray", 47, 79, 79 },
+    { "dark slate grey", 47, 79, 79 },
+    { "dark turquoise", 0, 206, 209 },
+    { "dark violet", 148, 0, 211 },
+    { "DarkBlue", 0, 0, 139 },
+    { "DarkCyan", 0, 139, 139 },
+    { "DarkGoldenrod", 184, 134, 11 },
+    { "DarkGoldenrod1", 255, 185, 15 },
+    { "DarkGoldenrod2", 238, 173, 14 },
+    { "DarkGoldenrod3", 205, 149, 12 },
+    { "DarkGoldenrod4", 139, 101, 8 },
+    { "DarkGray", 169, 169, 169 },
+    { "DarkGreen", 0, 100, 0 },
+    { "DarkGrey", 169, 169, 169 },
+    { "DarkKhaki", 189, 183, 107 },
+    { "DarkMagenta", 139, 0, 139 },
+    { "DarkOliveGreen", 85, 107, 47 },
+    { "DarkOliveGreen1", 202, 255, 112 },
+    { "DarkOliveGreen2", 188, 238, 104 },
+    { "DarkOliveGreen3", 162, 205, 90 },
+    { "DarkOliveGreen4", 110, 139, 61 },
+    { "DarkOrange", 255, 140, 0 },
+    { "DarkOrange1", 255, 127, 0 },
+    { "DarkOrange2", 238, 118, 0 },
+    { "DarkOrange3", 205, 102, 0 },
+    { "DarkOrange4", 139, 69, 0 },
+    { "DarkOrchid", 153, 50, 204 },
+    { "DarkOrchid1", 191, 62, 255 },
+    { "DarkOrchid2", 178, 58, 238 },
+    { "DarkOrchid3", 154, 50, 205 },
+    { "DarkOrchid4", 104, 34, 139 },
+    { "DarkRed", 139, 0, 0 },
+    { "DarkSalmon", 233, 150, 122 },
+    { "DarkSeaGreen", 143, 188, 143 },
+    { "DarkSeaGreen1", 193, 255, 193 },
+    { "DarkSeaGreen2", 180, 238, 180 },
+    { "DarkSeaGreen3", 155, 205, 155 },
+    { "DarkSeaGreen4", 105, 139, 105 },
+    { "DarkSlateBlue", 72, 61, 139 },
+    { "DarkSlateGray", 47, 79, 79 },
+    { "DarkSlateGray1", 151, 255, 255 },
+    { "DarkSlateGray2", 141, 238, 238 },
+    { "DarkSlateGray3", 121, 205, 205 },
+    { "DarkSlateGray4", 82, 139, 139 },
+    { "DarkSlateGrey", 47, 79, 79 },
+    { "DarkTurquoise", 0, 206, 209 },
+    { "DarkViolet", 148, 0, 211 },
+    { "deep pink", 255, 20, 147 },
+    { "deep sky blue", 0, 191, 255 },
+    { "DeepPink", 255, 20, 147 },
+    { "DeepPink1", 255, 20, 147 },
+    { "DeepPink2", 238, 18, 137 },
+    { "DeepPink3", 205, 16, 118 },
+    { "DeepPink4", 139, 10, 80 },
+    { "DeepSkyBlue", 0, 191, 255 },
+    { "DeepSkyBlue1", 0, 191, 255 },
+    { "DeepSkyBlue2", 0, 178, 238 },
+    { "DeepSkyBlue3", 0, 154, 205 },
+    { "DeepSkyBlue4", 0, 104, 139 },
+    { "dim gray", 105, 105, 105 },
+    { "dim grey", 105, 105, 105 },
+    { "DimGray", 105, 105, 105 },
+    { "DimGrey", 105, 105, 105 },
+    { "dodger blue", 30, 144, 255 },
+    { "DodgerBlue", 30, 144, 255 },
+    { "DodgerBlue1", 30, 144, 255 },
+    { "DodgerBlue2", 28, 134, 238 },
+    { "DodgerBlue3", 24, 116, 205 },
+    { "DodgerBlue4", 16, 78, 139 },
+    { "firebrick", 178, 34, 34 },
+    { "firebrick1", 255, 48, 48 },
+    { "firebrick2", 238, 44, 44 },
+    { "firebrick3", 205, 38, 38 },
+    { "firebrick4", 139, 26, 26 },
+    { "floral white", 255, 250, 240 },
+    { "FloralWhite", 255, 250, 240 },
+    { "forest green", 34, 139, 34 },
+    { "ForestGreen", 34, 139, 34 },
+    { "gainsboro", 220, 220, 220 },
+    { "ghost white", 248, 248, 255 },
+    { "GhostWhite", 248, 248, 255 },
+    { "gold", 255, 215, 0 },
+    { "gold1", 255, 215, 0 },
+    { "gold2", 238, 201, 0 },
+    { "gold3", 205, 173, 0 },
+    { "gold4", 139, 117, 0 },
+    { "goldenrod", 218, 165, 32 },
+    { "goldenrod1", 255, 193, 37 },
+    { "goldenrod2", 238, 180, 34 },
+    { "goldenrod3", 205, 155, 29 },
+    { "goldenrod4", 139, 105, 20 },
+    { "gray", 190, 190, 190 },
+    { "gray0", 0, 0, 0 },
+    { "gray1", 3, 3, 3 },
+    { "gray10", 26, 26, 26 },
+    { "gray100", 255, 255, 255 },
+    { "gray11", 28, 28, 28 },
+    { "gray12", 31, 31, 31 },
+    { "gray13", 33, 33, 33 },
+    { "gray14", 36, 36, 36 },
+    { "gray15", 38, 38, 38 },
+    { "gray16", 41, 41, 41 },
+    { "gray17", 43, 43, 43 },
+    { "gray18", 46, 46, 46 },
+    { "gray19", 48, 48, 48 },
+    { "gray2", 5, 5, 5 },
+    { "gray20", 51, 51, 51 },
+    { "gray21", 54, 54, 54 },
+    { "gray22", 56, 56, 56 },
+    { "gray23", 59, 59, 59 },
+    { "gray24", 61, 61, 61 },
+    { "gray25", 64, 64, 64 },
+    { "gray26", 66, 66, 66 },
+    { "gray27", 69, 69, 69 },
+    { "gray28", 71, 71, 71 },
+    { "gray29", 74, 74, 74 },
+    { "gray3", 8, 8, 8 },
+    { "gray30", 77, 77, 77 },
+    { "gray31", 79, 79, 79 },
+    { "gray32", 82, 82, 82 },
+    { "gray33", 84, 84, 84 },
+    { "gray34", 87, 87, 87 },
+    { "gray35", 89, 89, 89 },
+    { "gray36", 92, 92, 92 },
+    { "gray37", 94, 94, 94 },
+    { "gray38", 97, 97, 97 },
+    { "gray39", 99, 99, 99 },
+    { "gray4", 10, 10, 10 },
+    { "gray40", 102, 102, 102 },
+    { "gray41", 105, 105, 105 },
+    { "gray42", 107, 107, 107 },
+    { "gray43", 110, 110, 110 },
+    { "gray44", 112, 112, 112 },
+    { "gray45", 115, 115, 115 },
+    { "gray46", 117, 117, 117 },
+    { "gray47", 120, 120, 120 },
+    { "gray48", 122, 122, 122 },
+    { "gray49", 125, 125, 125 },
+    { "gray5", 13, 13, 13 },
+    { "gray50", 127, 127, 127 },
+    { "gray51", 130, 130, 130 },
+    { "gray52", 133, 133, 133 },
+    { "gray53", 135, 135, 135 },
+    { "gray54", 138, 138, 138 },
+    { "gray55", 140, 140, 140 },
+    { "gray56", 143, 143, 143 },
+    { "gray57", 145, 145, 145 },
+    { "gray58", 148, 148, 148 },
+    { "gray59", 150, 150, 150 },
+    { "gray6", 15, 15, 15 },
+    { "gray60", 153, 153, 153 },
+    { "gray61", 156, 156, 156 },
+    { "gray62", 158, 158, 158 },
+    { "gray63", 161, 161, 161 },
+    { "gray64", 163, 163, 163 },
+    { "gray65", 166, 166, 166 },
+    { "gray66", 168, 168, 168 },
+    { "gray67", 171, 171, 171 },
+    { "gray68", 173, 173, 173 },
+    { "gray69", 176, 176, 176 },
+    { "gray7", 18, 18, 18 },
+    { "gray70", 179, 179, 179 },
+    { "gray71", 181, 181, 181 },
+    { "gray72", 184, 184, 184 },
+    { "gray73", 186, 186, 186 },
+    { "gray74", 189, 189, 189 },
+    { "gray75", 191, 191, 191 },
+    { "gray76", 194, 194, 194 },
+    { "gray77", 196, 196, 196 },
+    { "gray78", 199, 199, 199 },
+    { "gray79", 201, 201, 201 },
+    { "gray8", 20, 20, 20 },
+    { "gray80", 204, 204, 204 },
+    { "gray81", 207, 207, 207 },
+    { "gray82", 209, 209, 209 },
+    { "gray83", 212, 212, 212 },
+    { "gray84", 214, 214, 214 },
+    { "gray85", 217, 217, 217 },
+    { "gray86", 219, 219, 219 },
+    { "gray87", 222, 222, 222 },
+    { "gray88", 224, 224, 224 },
+    { "gray89", 227, 227, 227 },
+    { "gray9", 23, 23, 23 },
+    { "gray90", 229, 229, 229 },
+    { "gray91", 232, 232, 232 },
+    { "gray92", 235, 235, 235 },
+    { "gray93", 237, 237, 237 },
+    { "gray94", 240, 240, 240 },
+    { "gray95", 242, 242, 242 },
+    { "gray96", 245, 245, 245 },
+    { "gray97", 247, 247, 247 },
+    { "gray98", 250, 250, 250 },
+    { "gray99", 252, 252, 252 },
+    { "green", 0, 255, 0 },
+    { "green yellow", 173, 255, 47 },
+    { "green1", 0, 255, 0 },
+    { "green2", 0, 238, 0 },
+    { "green3", 0, 205, 0 },
+    { "green4", 0, 139, 0 },
+    { "GreenYellow", 173, 255, 47 },
+    { "grey", 190, 190, 190 },
+    { "grey0", 0, 0, 0 },
+    { "grey1", 3, 3, 3 },
+    { "grey10", 26, 26, 26 },
+    { "grey100", 255, 255, 255 },
+    { "grey11", 28, 28, 28 },
+    { "grey12", 31, 31, 31 },
+    { "grey13", 33, 33, 33 },
+    { "grey14", 36, 36, 36 },
+    { "grey15", 38, 38, 38 },
+    { "grey16", 41, 41, 41 },
+    { "grey17", 43, 43, 43 },
+    { "grey18", 46, 46, 46 },
+    { "grey19", 48, 48, 48 },
+    { "grey2", 5, 5, 5 },
+    { "grey20", 51, 51, 51 },
+    { "grey21", 54, 54, 54 },
+    { "grey22", 56, 56, 56 },
+    { "grey23", 59, 59, 59 },
+    { "grey24", 61, 61, 61 },
+    { "grey25", 64, 64, 64 },
+    { "grey26", 66, 66, 66 },
+    { "grey27", 69, 69, 69 },
+    { "grey28", 71, 71, 71 },
+    { "grey29", 74, 74, 74 },
+    { "grey3", 8, 8, 8 },
+    { "grey30", 77, 77, 77 },
+    { "grey31", 79, 79, 79 },
+    { "grey32", 82, 82, 82 },
+    { "grey33", 84, 84, 84 },
+    { "grey34", 87, 87, 87 },
+    { "grey35", 89, 89, 89 },
+    { "grey36", 92, 92, 92 },
+    { "grey37", 94, 94, 94 },
+    { "grey38", 97, 97, 97 },
+    { "grey39", 99, 99, 99 },
+    { "grey4", 10, 10, 10 },
+    { "grey40", 102, 102, 102 },
+    { "grey41", 105, 105, 105 },
+    { "grey42", 107, 107, 107 },
+    { "grey43", 110, 110, 110 },
+    { "grey44", 112, 112, 112 },
+    { "grey45", 115, 115, 115 },
+    { "grey46", 117, 117, 117 },
+    { "grey47", 120, 120, 120 },
+    { "grey48", 122, 122, 122 },
+    { "grey49", 125, 125, 125 },
+    { "grey5", 13, 13, 13 },
+    { "grey50", 127, 127, 127 },
+    { "grey51", 130, 130, 130 },
+    { "grey52", 133, 133, 133 },
+    { "grey53", 135, 135, 135 },
+    { "grey54", 138, 138, 138 },
+    { "grey55", 140, 140, 140 },
+    { "grey56", 143, 143, 143 },
+    { "grey57", 145, 145, 145 },
+    { "grey58", 148, 148, 148 },
+    { "grey59", 150, 150, 150 },
+    { "grey6", 15, 15, 15 },
+    { "grey60", 153, 153, 153 },
+    { "grey61", 156, 156, 156 },
+    { "grey62", 158, 158, 158 },
+    { "grey63", 161, 161, 161 },
+    { "grey64", 163, 163, 163 },
+    { "grey65", 166, 166, 166 },
+    { "grey66", 168, 168, 168 },
+    { "grey67", 171, 171, 171 },
+    { "grey68", 173, 173, 173 },
+    { "grey69", 176, 176, 176 },
+    { "grey7", 18, 18, 18 },
+    { "grey70", 179, 179, 179 },
+    { "grey71", 181, 181, 181 },
+    { "grey72", 184, 184, 184 },
+    { "grey73", 186, 186, 186 },
+    { "grey74", 189, 189, 189 },
+    { "grey75", 191, 191, 191 },
+    { "grey76", 194, 194, 194 },
+    { "grey77", 196, 196, 196 },
+    { "grey78", 199, 199, 199 },
+    { "grey79", 201, 201, 201 },
+    { "grey8", 20, 20, 20 },
+    { "grey80", 204, 204, 204 },
+    { "grey81", 207, 207, 207 },
+    { "grey82", 209, 209, 209 },
+    { "grey83", 212, 212, 212 },
+    { "grey84", 214, 214, 214 },
+    { "grey85", 217, 217, 217 },
+    { "grey86", 219, 219, 219 },
+    { "grey87", 222, 222, 222 },
+    { "grey88", 224, 224, 224 },
+    { "grey89", 227, 227, 227 },
+    { "grey9", 23, 23, 23 },
+    { "grey90", 229, 229, 229 },
+    { "grey91", 232, 232, 232 },
+    { "grey92", 235, 235, 235 },
+    { "grey93", 237, 237, 237 },
+    { "grey94", 240, 240, 240 },
+    { "grey95", 242, 242, 242 },
+    { "grey96", 245, 245, 245 },
+    { "grey97", 247, 247, 247 },
+    { "grey98", 250, 250, 250 },
+    { "grey99", 252, 252, 252 },
+    { "honeydew", 240, 255, 240 },
+    { "honeydew1", 240, 255, 240 },
+    { "honeydew2", 224, 238, 224 },
+    { "honeydew3", 193, 205, 193 },
+    { "honeydew4", 131, 139, 131 },
+    { "hot pink", 255, 105, 180 },
+    { "HotPink", 255, 105, 180 },
+    { "HotPink1", 255, 110, 180 },
+    { "HotPink2", 238, 106, 167 },
+    { "HotPink3", 205, 96, 144 },
+    { "HotPink4", 139, 58, 98 },
+    { "indian red", 205, 92, 92 },
+    { "IndianRed", 205, 92, 92 },
+    { "IndianRed1", 255, 106, 106 },
+    { "IndianRed2", 238, 99, 99 },
+    { "IndianRed3", 205, 85, 85 },
+    { "IndianRed4", 139, 58, 58 },
+    { "ivory", 255, 255, 240 },
+    { "ivory1", 255, 255, 240 },
+    { "ivory2", 238, 238, 224 },
+    { "ivory3", 205, 205, 193 },
+    { "ivory4", 139, 139, 131 },
+    { "khaki", 240, 230, 140 },
+    { "khaki1", 255, 246, 143 },
+    { "khaki2", 238, 230, 133 },
+    { "khaki3", 205, 198, 115 },
+    { "khaki4", 139, 134, 78 },
+    { "lavender", 230, 230, 250 },
+    { "lavender blush", 255, 240, 245 },
+    { "LavenderBlush", 255, 240, 245 },
+    { "LavenderBlush1", 255, 240, 245 },
+    { "LavenderBlush2", 238, 224, 229 },
+    { "LavenderBlush3", 205, 193, 197 },
+    { "LavenderBlush4", 139, 131, 134 },
+    { "lawn green", 124, 252, 0 },
+    { "LawnGreen", 124, 252, 0 },
+    { "lemon chiffon", 255, 250, 205 },
+    { "LemonChiffon", 255, 250, 205 },
+    { "LemonChiffon1", 255, 250, 205 },
+    { "LemonChiffon2", 238, 233, 191 },
+    { "LemonChiffon3", 205, 201, 165 },
+    { "LemonChiffon4", 139, 137, 112 },
+    { "light blue", 173, 216, 230 },
+    { "light coral", 240, 128, 128 },
+    { "light cyan", 224, 255, 255 },
+    { "light goldenrod", 238, 221, 130 },
+    { "light goldenrod yellow", 250, 250, 210 },
+    { "light gray", 211, 211, 211 },
+    { "light green", 144, 238, 144 },
+    { "light grey", 211, 211, 211 },
+    { "light pink", 255, 182, 193 },
+    { "light salmon", 255, 160, 122 },
+    { "light sea green", 32, 178, 170 },
+    { "light sky blue", 135, 206, 250 },
+    { "light slate blue", 132, 112, 255 },
+    { "light slate gray", 119, 136, 153 },
+    { "light slate grey", 119, 136, 153 },
+    { "light steel blue", 176, 196, 222 },
+    { "light yellow", 255, 255, 224 },
+    { "LightBlue", 173, 216, 230 },
+    { "LightBlue1", 191, 239, 255 },
+    { "LightBlue2", 178, 223, 238 },
+    { "LightBlue3", 154, 192, 205 },
+    { "LightBlue4", 104, 131, 139 },
+    { "LightCoral", 240, 128, 128 },
+    { "LightCyan", 224, 255, 255 },
+    { "LightCyan1", 224, 255, 255 },
+    { "LightCyan2", 209, 238, 238 },
+    { "LightCyan3", 180, 205, 205 },
+    { "LightCyan4", 122, 139, 139 },
+    { "LightGoldenrod", 238, 221, 130 },
+    { "LightGoldenrod1", 255, 236, 139 },
+    { "LightGoldenrod2", 238, 220, 130 },
+    { "LightGoldenrod3", 205, 190, 112 },
+    { "LightGoldenrod4", 139, 129, 76 },
+    { "LightGoldenrodYellow", 250, 250, 210 },
+    { "LightGray", 211, 211, 211 },
+    { "LightGreen", 144, 238, 144 },
+    { "LightGrey", 211, 211, 211 },
+    { "LightPink", 255, 182, 193 },
+    { "LightPink1", 255, 174, 185 },
+    { "LightPink2", 238, 162, 173 },
+    { "LightPink3", 205, 140, 149 },
+    { "LightPink4", 139, 95, 101 },
+    { "LightSalmon", 255, 160, 122 },
+    { "LightSalmon1", 255, 160, 122 },
+    { "LightSalmon2", 238, 149, 114 },
+    { "LightSalmon3", 205, 129, 98 },
+    { "LightSalmon4", 139, 87, 66 },
+    { "LightSeaGreen", 32, 178, 170 },
+    { "LightSkyBlue", 135, 206, 250 },
+    { "LightSkyBlue1", 176, 226, 255 },
+    { "LightSkyBlue2", 164, 211, 238 },
+    { "LightSkyBlue3", 141, 182, 205 },
+    { "LightSkyBlue4", 96, 123, 139 },
+    { "LightSlateBlue", 132, 112, 255 },
+    { "LightSlateGray", 119, 136, 153 },
+    { "LightSlateGrey", 119, 136, 153 },
+    { "LightSteelBlue", 176, 196, 222 },
+    { "LightSteelBlue1", 202, 225, 255 },
+    { "LightSteelBlue2", 188, 210, 238 },
+    { "LightSteelBlue3", 162, 181, 205 },
+    { "LightSteelBlue4", 110, 123, 139 },
+    { "LightYellow", 255, 255, 224 },
+    { "LightYellow1", 255, 255, 224 },
+    { "LightYellow2", 238, 238, 209 },
+    { "LightYellow3", 205, 205, 180 },
+    { "LightYellow4", 139, 139, 122 },
+    { "lime green", 50, 205, 50 },
+    { "LimeGreen", 50, 205, 50 },
+    { "linen", 250, 240, 230 },
+    { "magenta", 255, 0, 255 },
+    { "magenta1", 255, 0, 255 },
+    { "magenta2", 238, 0, 238 },
+    { "magenta3", 205, 0, 205 },
+    { "magenta4", 139, 0, 139 },
+    { "maroon", 176, 48, 96 },
+    { "maroon1", 255, 52, 179 },
+    { "maroon2", 238, 48, 167 },
+    { "maroon3", 205, 41, 144 },
+    { "maroon4", 139, 28, 98 },
+    { "medium aquamarine", 102, 205, 170 },
+    { "medium blue", 0, 0, 205 },
+    { "medium orchid", 186, 85, 211 },
+    { "medium purple", 147, 112, 219 },
+    { "medium sea green", 60, 179, 113 },
+    { "medium slate blue", 123, 104, 238 },
+    { "medium spring green", 0, 250, 154 },
+    { "medium turquoise", 72, 209, 204 },
+    { "medium violet red", 199, 21, 133 },
+    { "MediumAquamarine", 102, 205, 170 },
+    { "MediumBlue", 0, 0, 205 },
+    { "MediumOrchid", 186, 85, 211 },
+    { "MediumOrchid1", 224, 102, 255 },
+    { "MediumOrchid2", 209, 95, 238 },
+    { "MediumOrchid3", 180, 82, 205 },
+    { "MediumOrchid4", 122, 55, 139 },
+    { "MediumPurple", 147, 112, 219 },
+    { "MediumPurple1", 171, 130, 255 },
+    { "MediumPurple2", 159, 121, 238 },
+    { "MediumPurple3", 137, 104, 205 },
+    { "MediumPurple4", 93, 71, 139 },
+    { "MediumSeaGreen", 60, 179, 113 },
+    { "MediumSlateBlue", 123, 104, 238 },
+    { "MediumSpringGreen", 0, 250, 154 },
+    { "MediumTurquoise", 72, 209, 204 },
+    { "MediumVioletRed", 199, 21, 133 },
+    { "midnight blue", 25, 25, 112 },
+    { "MidnightBlue", 25, 25, 112 },
+    { "mint cream", 245, 255, 250 },
+    { "MintCream", 245, 255, 250 },
+    { "misty rose", 255, 228, 225 },
+    { "MistyRose", 255, 228, 225 },
+    { "MistyRose1", 255, 228, 225 },
+    { "MistyRose2", 238, 213, 210 },
+    { "MistyRose3", 205, 183, 181 },
+    { "MistyRose4", 139, 125, 123 },
+    { "moccasin", 255, 228, 181 },
+    { "navajo white", 255, 222, 173 },
+    { "NavajoWhite", 255, 222, 173 },
+    { "NavajoWhite1", 255, 222, 173 },
+    { "NavajoWhite2", 238, 207, 161 },
+    { "NavajoWhite3", 205, 179, 139 },
+    { "NavajoWhite4", 139, 121, 94 },
+    { "navy", 0, 0, 128 },
+    { "navy blue", 0, 0, 128 },
+    { "NavyBlue", 0, 0, 128 },
+    { "old lace", 253, 245, 230 },
+    { "OldLace", 253, 245, 230 },
+    { "olive drab", 107, 142, 35 },
+    { "OliveDrab", 107, 142, 35 },
+    { "OliveDrab1", 192, 255, 62 },
+    { "OliveDrab2", 179, 238, 58 },
+    { "OliveDrab3", 154, 205, 50 },
+    { "OliveDrab4", 105, 139, 34 },
+    { "orange", 255, 165, 0 },
+    { "orange red", 255, 69, 0 },
+    { "orange1", 255, 165, 0 },
+    { "orange2", 238, 154, 0 },
+    { "orange3", 205, 133, 0 },
+    { "orange4", 139, 90, 0 },
+    { "OrangeRed", 255, 69, 0 },
+    { "OrangeRed1", 255, 69, 0 },
+    { "OrangeRed2", 238, 64, 0 },
+    { "OrangeRed3", 205, 55, 0 },
+    { "OrangeRed4", 139, 37, 0 },
+    { "orchid", 218, 112, 214 },
+    { "orchid1", 255, 131, 250 },
+    { "orchid2", 238, 122, 233 },
+    { "orchid3", 205, 105, 201 },
+    { "orchid4", 139, 71, 137 },
+    { "pale goldenrod", 238, 232, 170 },
+    { "pale green", 152, 251, 152 },
+    { "pale turquoise", 175, 238, 238 },
+    { "pale violet red", 219, 112, 147 },
+    { "PaleGoldenrod", 238, 232, 170 },
+    { "PaleGreen", 152, 251, 152 },
+    { "PaleGreen1", 154, 255, 154 },
+    { "PaleGreen2", 144, 238, 144 },
+    { "PaleGreen3", 124, 205, 124 },
+    { "PaleGreen4", 84, 139, 84 },
+    { "PaleTurquoise", 175, 238, 238 },
+    { "PaleTurquoise1", 187, 255, 255 },
+    { "PaleTurquoise2", 174, 238, 238 },
+    { "PaleTurquoise3", 150, 205, 205 },
+    { "PaleTurquoise4", 102, 139, 139 },
+    { "PaleVioletRed", 219, 112, 147 },
+    { "PaleVioletRed1", 255, 130, 171 },
+    { "PaleVioletRed2", 238, 121, 159 },
+    { "PaleVioletRed3", 205, 104, 137 },
+    { "PaleVioletRed4", 139, 71, 93 },
+    { "papaya whip", 255, 239, 213 },
+    { "PapayaWhip", 255, 239, 213 },
+    { "peach puff", 255, 218, 185 },
+    { "PeachPuff", 255, 218, 185 },
+    { "PeachPuff1", 255, 218, 185 },
+    { "PeachPuff2", 238, 203, 173 },
+    { "PeachPuff3", 205, 175, 149 },
+    { "PeachPuff4", 139, 119, 101 },
+    { "peru", 205, 133, 63 },
+    { "pink", 255, 192, 203 },
+    { "pink1", 255, 181, 197 },
+    { "pink2", 238, 169, 184 },
+    { "pink3", 205, 145, 158 },
+    { "pink4", 139, 99, 108 },
+    { "plum", 221, 160, 221 },
+    { "plum1", 255, 187, 255 },
+    { "plum2", 238, 174, 238 },
+    { "plum3", 205, 150, 205 },
+    { "plum4", 139, 102, 139 },
+    { "powder blue", 176, 224, 230 },
+    { "PowderBlue", 176, 224, 230 },
+    { "purple", 160, 32, 240 },
+    { "purple1", 155, 48, 255 },
+    { "purple2", 145, 44, 238 },
+    { "purple3", 125, 38, 205 },
+    { "purple4", 85, 26, 139 },
+    { "red", 255, 0, 0 },
+    { "red1", 255, 0, 0 },
+    { "red2", 238, 0, 0 },
+    { "red3", 205, 0, 0 },
+    { "red4", 139, 0, 0 },
+    { "rosy brown", 188, 143, 143 },
+    { "RosyBrown", 188, 143, 143 },
+    { "RosyBrown1", 255, 193, 193 },
+    { "RosyBrown2", 238, 180, 180 },
+    { "RosyBrown3", 205, 155, 155 },
+    { "RosyBrown4", 139, 105, 105 },
+    { "royal blue", 65, 105, 225 },
+    { "RoyalBlue", 65, 105, 225 },
+    { "RoyalBlue1", 72, 118, 255 },
+    { "RoyalBlue2", 67, 110, 238 },
+    { "RoyalBlue3", 58, 95, 205 },
+    { "RoyalBlue4", 39, 64, 139 },
+    { "saddle brown", 139, 69, 19 },
+    { "SaddleBrown", 139, 69, 19 },
+    { "salmon", 250, 128, 114 },
+    { "salmon1", 255, 140, 105 },
+    { "salmon2", 238, 130, 98 },
+    { "salmon3", 205, 112, 84 },
+    { "salmon4", 139, 76, 57 },
+    { "sandy brown", 244, 164, 96 },
+    { "SandyBrown", 244, 164, 96 },
+    { "sea green", 46, 139, 87 },
+    { "SeaGreen", 46, 139, 87 },
+    { "SeaGreen1", 84, 255, 159 },
+    { "SeaGreen2", 78, 238, 148 },
+    { "SeaGreen3", 67, 205, 128 },
+    { "SeaGreen4", 46, 139, 87 },
+    { "seashell", 255, 245, 238 },
+    { "seashell1", 255, 245, 238 },
+    { "seashell2", 238, 229, 222 },
+    { "seashell3", 205, 197, 191 },
+    { "seashell4", 139, 134, 130 },
+    { "sienna", 160, 82, 45 },
+    { "sienna1", 255, 130, 71 },
+    { "sienna2", 238, 121, 66 },
+    { "sienna3", 205, 104, 57 },
+    { "sienna4", 139, 71, 38 },
+    { "sky blue", 135, 206, 235 },
+    { "SkyBlue", 135, 206, 235 },
+    { "SkyBlue1", 135, 206, 255 },
+    { "SkyBlue2", 126, 192, 238 },
+    { "SkyBlue3", 108, 166, 205 },
+    { "SkyBlue4", 74, 112, 139 },
+    { "slate blue", 106, 90, 205 },
+    { "slate gray", 112, 128, 144 },
+    { "slate grey", 112, 128, 144 },
+    { "SlateBlue", 106, 90, 205 },
+    { "SlateBlue1", 131, 111, 255 },
+    { "SlateBlue2", 122, 103, 238 },
+    { "SlateBlue3", 105, 89, 205 },
+    { "SlateBlue4", 71, 60, 139 },
+    { "SlateGray", 112, 128, 144 },
+    { "SlateGray1", 198, 226, 255 },
+    { "SlateGray2", 185, 211, 238 },
+    { "SlateGray3", 159, 182, 205 },
+    { "SlateGray4", 108, 123, 139 },
+    { "SlateGrey", 112, 128, 144 },
+    { "snow", 255, 250, 250 },
+    { "snow1", 255, 250, 250 },
+    { "snow2", 238, 233, 233 },
+    { "snow3", 205, 201, 201 },
+    { "snow4", 139, 137, 137 },
+    { "spring green", 0, 255, 127 },
+    { "SpringGreen", 0, 255, 127 },
+    { "SpringGreen1", 0, 255, 127 },
+    { "SpringGreen2", 0, 238, 118 },
+    { "SpringGreen3", 0, 205, 102 },
+    { "SpringGreen4", 0, 139, 69 },
+    { "steel blue", 70, 130, 180 },
+    { "SteelBlue", 70, 130, 180 },
+    { "SteelBlue1", 99, 184, 255 },
+    { "SteelBlue2", 92, 172, 238 },
+    { "SteelBlue3", 79, 148, 205 },
+    { "SteelBlue4", 54, 100, 139 },
+    { "tan", 210, 180, 140 },
+    { "tan1", 255, 165, 79 },
+    { "tan2", 238, 154, 73 },
+    { "tan3", 205, 133, 63 },
+    { "tan4", 139, 90, 43 },
+    { "thistle", 216, 191, 216 },
+    { "thistle1", 255, 225, 255 },
+    { "thistle2", 238, 210, 238 },
+    { "thistle3", 205, 181, 205 },
+    { "thistle4", 139, 123, 139 },
+    { "tomato", 255, 99, 71 },
+    { "tomato1", 255, 99, 71 },
+    { "tomato2", 238, 92, 66 },
+    { "tomato3", 205, 79, 57 },
+    { "tomato4", 139, 54, 38 },
+    { "turquoise", 64, 224, 208 },
+    { "turquoise1", 0, 245, 255 },
+    { "turquoise2", 0, 229, 238 },
+    { "turquoise3", 0, 197, 205 },
+    { "turquoise4", 0, 134, 139 },
+    { "violet", 238, 130, 238 },
+    { "violet red", 208, 32, 144 },
+    { "VioletRed", 208, 32, 144 },
+    { "VioletRed1", 255, 62, 150 },
+    { "VioletRed2", 238, 58, 140 },
+    { "VioletRed3", 205, 50, 120 },
+    { "VioletRed4", 139, 34, 82 },
+    { "wheat", 245, 222, 179 },
+    { "wheat1", 255, 231, 186 },
+    { "wheat2", 238, 216, 174 },
+    { "wheat3", 205, 186, 150 },
+    { "wheat4", 139, 126, 102 },
+    { "white", 255, 255, 255 },
+    { "white smoke", 245, 245, 245 },
+    { "WhiteSmoke", 245, 245, 245 },
+    { "yellow", 255, 255, 0 },
+    { "yellow green", 154, 205, 50 },
+    { "yellow1", 255, 255, 0 },
+    { "yellow2", 238, 238, 0 },
+    { "yellow3", 205, 205, 0 },
+    { "yellow4", 139, 139, 0 },
+    { "YellowGreen", 154, 205, 50 }
+};
+#define numXColors (sizeof (xColors) / sizeof (*xColors))
+/*
+ *----------------------------------------------------------------------
+ *
+ * FindColor --
+ *
+ *     This routine finds the color entry that corresponds to the
+ *     specified color.
+ *
+ * Results:
+ *     Returns non-zero on success.  The RGB values of the XColor
+ *     will be initialized to the proper values on success.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+compare_xcolor_entries (const void *a, const void *b)
+{
+  return strcasecmp ((const char *) a, ((const XColorEntry *) b)->name);
+}
+
+static int
+FindColor(const char *name,
+         GdkColor   *colorPtr)
+{
+  XColorEntry *found;
+
+  found = bsearch (name, xColors, numXColors, sizeof (XColorEntry),
+                  compare_xcolor_entries);
+  if (found == NULL)
+    return 0;
+  
+  colorPtr->red = (found->red * 65535) / 255;
+  colorPtr->green = (found->green * 65535) / 255;
+  colorPtr->blue = (found->blue * 65535) / 255;
+  return 1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * parse_color --
+ *
+ *     Partial implementation of X color name parsing interface.
+ *
+ * Results:
+ *     Returns non-zero on success.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+gboolean
+parse_color(Colormap    map,
+           const char *spec,
+           GdkColor   *colorPtr)
+{
+    if (spec[0] == '#') {
+       char fmt[16];
+       int i, red, green, blue;
+
+       if ((i = strlen(spec+1))%3) {
+           return 0;
+       }
+       i /= 3;
+
+       sprintf(fmt, "%%%dx%%%dx%%%dx", i, i, i);
+       if (sscanf(spec+1, fmt, &red, &green, &blue) != 3) {
+           return 0;
+       }
+       if (i == 4)
+         {
+           colorPtr->red = red;
+           colorPtr->green = green;
+           colorPtr->blue = blue;
+         }
+       else if (i == 1)
+         {
+           colorPtr->red = (red * 65535) / 15;
+           colorPtr->green = (green * 65535) / 15;
+           colorPtr->blue = (blue * 65535) / 15;
+         }
+       else if (i == 2)
+         {
+           colorPtr->red = (red * 65535) / 255;
+           colorPtr->green = (green * 65535) / 255;
+           colorPtr->blue = (blue * 65535) / 255;
+         }
+       else /* if (i == 3) */
+         {
+           colorPtr->red = (red * 65535) / 4095;
+           colorPtr->green = (green * 65535) / 4095;
+           colorPtr->blue = (blue * 65535) / 4095;
+         }
+    } else {
+       if (!FindColor(spec, colorPtr)) {
+           return 0;
+       }
+    }
+    return 1;
+}
+
+/* End of code from Tk8.0 */
+
+static Colormap
+DefaultColormap ()
+{
+  static Colormap colormap;
+  gint i;
+
+  if (colormap)
+    return colormap;
+
+  colormap = create_colormap ( NULL, NULL, AllocNone);
+  return colormap;
+}
+
+\f
+GdkColormap*
+gdk_colormap_new (GdkVisual *visual,
+                 gint       private_cmap)
+{
+  GdkColormap *colormap;
+  GdkColormapPrivate *private;
+  Visual *xvisual;
+  int size;
+  unsigned int i;
+
+  g_return_val_if_fail (visual != NULL, NULL);
+
+  private = g_new (GdkColormapPrivate, 1);
+  colormap = (GdkColormap*) private;
+
+  private->visual = visual;
+  private->ref_count = 1;
+
+  private->hash = NULL;
+  private->last_sync_time = 0;
+  private->info = NULL;
+  
+  xvisual = ((GdkVisualPrivate*) visual)->xvisual;
+
+  colormap->size = visual->colormap_size;
+  colormap->colors = g_new (GdkColor, colormap->size);
+
+  switch (visual->type)
+    {
+    case GDK_VISUAL_GRAYSCALE:
+    case GDK_VISUAL_PSEUDO_COLOR:
+      private->info = g_new0 (GdkColorInfo, colormap->size);
+      colormap->colors = g_new (GdkColor, colormap->size);
+      
+      private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
+                                       (GCompareFunc) gdk_color_equal);
+      
+      private->private_val = private_cmap;
+      private->xcolormap = create_colormap (gdk_root_window, xvisual,
+                                           (private_cmap) ? (AllocAll) : (AllocNone));
+
+      if (private_cmap)
+       {
+         PALETTEENTRY pal[256];
+         guint npal;
+
+         npal = GetPaletteEntries (private->xcolormap->palette, 0, colormap->size, pal);
+         for (i = 0; i < colormap->size; i++)
+           {
+             colormap->colors[i].pixel = i;
+             if (i >= npal)
+               {
+                 colormap->colors[i].red =
+                   colormap->colors[i].green =
+                   colormap->colors[i].blue = 0;
+               }
+             else
+               {
+                 colormap->colors[i].red = (pal[i].peRed * 65535) / 255;
+                 colormap->colors[i].green = (pal[i].peGreen * 65525) / 255;
+                 colormap->colors[i].blue = (pal[i].peBlue * 65535) / 255;
+               }
+           }
+         gdk_colormap_change (colormap, colormap->size);
+       }
+      break;
+
+    case GDK_VISUAL_STATIC_GRAY:
+    case GDK_VISUAL_STATIC_COLOR:
+    case GDK_VISUAL_TRUE_COLOR:
+      private->private_val = FALSE;
+      private->xcolormap = create_colormap (gdk_root_window,
+                                           xvisual, AllocNone);
+      break;
+    }
+
+  gdk_colormap_add (colormap);
+
+  return colormap;
+}
+
+static void
+gdk_colormap_real_destroy (GdkColormap *colormap)
+{
+  GdkColormapPrivate *private = (GdkColormapPrivate*) colormap;
+
+  g_return_if_fail (colormap != NULL);
+  g_return_if_fail (private->ref_count == 0);
+
+  gdk_colormap_remove (colormap);
+  XFreeColormap (private->xcolormap);
+
+  if (private->hash)
+    g_hash_table_destroy (private->hash);
+  
+  g_free (private->info);
+  g_free (colormap->colors);
+  g_free (colormap);
+}
+
+GdkColormap*
+gdk_colormap_ref (GdkColormap *cmap)
+{
+  GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
+
+  g_return_val_if_fail (cmap != NULL, NULL);
+
+  private->ref_count += 1;
+  return cmap;
+}
+
+void
+gdk_colormap_unref (GdkColormap *cmap)
+{
+  GdkColormapPrivate *private = (GdkColormapPrivate *)cmap;
+
+  g_return_if_fail (cmap != NULL);
+  g_return_if_fail (private->ref_count > 0);
+
+  private->ref_count -= 1;
+  if (private->ref_count == 0)
+    gdk_colormap_real_destroy (cmap);
+}
+
+#define MIN_SYNC_TIME 2
+
+GdkVisual *
+gdk_colormap_get_visual (GdkColormap *colormap)
+{
+  GdkColormapPrivate *private;
+
+  g_return_val_if_fail (colormap != NULL, NULL);
+  
+  private = (GdkColormapPrivate *)colormap;
+
+  return private->visual;
+}
+     
+void
+gdk_colormap_sync (GdkColormap *colormap,
+                  gboolean     force)
+{
+  time_t current_time;
+  GdkColormapPrivate *private = (GdkColormapPrivate *)colormap;
+  XColor *xpalette;
+  gint nlookup;
+  gint i;
+  
+  g_return_if_fail (colormap != NULL);
+
+  current_time = time (NULL);
+  if (!force && ((current_time - private->last_sync_time) < MIN_SYNC_TIME))
+    return;
+
+  private->last_sync_time = current_time;
+
+  nlookup = 0;
+  xpalette = g_new (XColor, colormap->size);
+  
+  nlookup = GetPaletteEntries (private->xcolormap->palette,
+                              0, colormap->size, xpalette);
+  
+  for (i = 0; i < nlookup; i++)
+    {
+      colormap->colors[i].pixel = i;
+      colormap->colors[i].red = (xpalette[i].peRed * 65535) / 255;
+      colormap->colors[i].green = (xpalette[i].peGreen * 65535) / 255;
+      colormap->colors[i].blue = (xpalette[i].peBlue * 65535) / 255;
+    }
+
+  g_free (xpalette);
+}
+                  
+
+GdkColormap*
+gdk_colormap_get_system (void)
+{
+  static GdkColormap *colormap = NULL;
+  GdkColormapPrivate *private;
+  gint i;
+
+  if (!colormap)
+    {
+      private = g_new (GdkColormapPrivate, 1);
+      colormap = (GdkColormap*) private;
+
+      private->xcolormap = DefaultColormap ();
+      private->visual = gdk_visual_get_system ();
+      private->private_val = FALSE;
+      private->ref_count = 1;
+
+      private->hash = NULL;
+      private->last_sync_time = 0;
+      private->info = NULL;
+
+      colormap->colors = NULL;
+      colormap->size = private->visual->colormap_size;
+
+      if ((private->visual->type == GDK_VISUAL_GRAYSCALE) ||
+         (private->visual->type == GDK_VISUAL_PSEUDO_COLOR))
+       {
+         private->info = g_new0 (GdkColorInfo, colormap->size);
+         colormap->colors = g_new (GdkColor, colormap->size);
+         
+         private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
+                                           (GCompareFunc) gdk_color_equal);
+
+         gdk_colormap_sync (colormap, TRUE);
+       }
+      gdk_colormap_add (colormap);
+    }
+
+  return colormap;
+}
+
+gint
+gdk_colormap_get_system_size (void)
+{
+  gint bitspixel;
+  
+  bitspixel = GetDeviceCaps (gdk_DC, BITSPIXEL);
+
+  if (bitspixel == 1)
+    return 2;
+  else if (bitspixel == 4)
+    return 16;
+  else if (bitspixel == 8)
+    return 256;
+  else if (bitspixel == 12)
+    return 32;
+  else if (bitspixel == 16)
+    return 64;
+  else /* if (bitspixel >= 24) */
+    return 256;
+}
+
+void
+gdk_colormap_change (GdkColormap *colormap,
+                    gint         ncolors)
+{
+  GdkColormapPrivate *private;
+  GdkVisual *visual;
+  XColor *palette;
+  gint shift;
+  int max_colors;
+  int size;
+  int i;
+
+  g_return_if_fail (colormap != NULL);
+
+  palette = g_new (XColor, ncolors);
+
+  private = (GdkColormapPrivate*) colormap;
+  switch (private->visual->type)
+    {
+    case GDK_VISUAL_GRAYSCALE:
+    case GDK_VISUAL_PSEUDO_COLOR:
+      for (i = 0; i < ncolors; i++)
+       {
+         palette[i].peRed = (colormap->colors[i].red >> 8);
+         palette[i].peGreen = (colormap->colors[i].green >> 8);
+         palette[i].peBlue = (colormap->colors[i].blue >> 8);
+         palette[i].peFlags = 0;
+       }
+
+      if (SetPaletteEntries (private->xcolormap->palette,
+                            0, ncolors, palette) == 0)
+       g_warning ("gdk_colormap_change: SetPaletteEntries failed");
+      private->xcolormap->stale = TRUE;
+      break;
+
+    default:
+      break;
+    }
+
+  g_free (palette);
+}
+
+void
+gdk_colors_store (GdkColormap   *colormap,
+                 GdkColor      *colors,
+                 gint           ncolors)
+{
+  gint i;
+
+  for (i = 0; i < ncolors; i++)
+    {
+      colormap->colors[i].pixel = colors[i].pixel;
+      colormap->colors[i].red = colors[i].red;
+      colormap->colors[i].green = colors[i].green;
+      colormap->colors[i].blue = colors[i].blue;
+    }
+
+  gdk_colormap_change (colormap, ncolors);
+}
+
+gboolean
+gdk_colors_alloc (GdkColormap   *colormap,
+                 gint           contiguous,
+                 gulong        *planes,
+                 gint           nplanes,
+                 gulong        *pixels,
+                 gint           npixels)
+{
+  GdkColormapPrivate *private;
+  gint return_val;
+  gint i;
+
+  g_return_val_if_fail (colormap != NULL, 0);
+
+  private = (GdkColormapPrivate*) colormap;
+
+  return_val = alloc_color_cells (private->xcolormap, contiguous,
+                                 planes, nplanes, pixels, npixels);
+
+  if (return_val)
+    {
+      for (i=0; i<npixels; i++)
+       {
+         private->info[pixels[i]].ref_count++;
+         private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE;
+       }
+    }
+
+  return return_val;
+}
+
+/* This is almost identical to gdk_colormap_free_colors.
+ * Keep them in sync!
+ */
+void
+gdk_colors_free (GdkColormap *colormap,
+                gulong      *in_pixels,
+                gint         in_npixels,
+                gulong       planes)
+{
+  GdkColormapPrivate *private;
+  gulong *pixels;
+  gint npixels = 0;
+  gint i;
+
+  g_return_if_fail (colormap != NULL);
+  g_return_if_fail (in_pixels != NULL);
+
+  private = (GdkColormapPrivate*) colormap;
+
+  if ((private->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
+      (private->visual->type != GDK_VISUAL_GRAYSCALE))
+    return;
+  
+  pixels = g_new (gulong, in_npixels);
+
+  for (i=0; i<in_npixels; i++)
+    {
+      gulong pixel = in_pixels[i];
+      
+      if (private->info[pixel].ref_count)
+       {
+         private->info[pixel].ref_count--;
+
+         if (private->info[pixel].ref_count == 0)
+           {
+             pixels[npixels++] = pixel;
+             if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
+               g_hash_table_remove (private->hash, &colormap->colors[in_pixels[i]]);
+             private->info[pixel].flags = 0;
+           }
+       }
+    }
+
+
+  if (npixels)
+    XFreeColors (private->xcolormap, pixels, npixels, planes);
+
+  g_free (pixels);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_color_copy
+ *
+ *   Copy a color structure into new storage.
+ *
+ * Arguments:
+ *   "color" is the color struct to copy.
+ *
+ * Results:
+ *   A new color structure.  Free it with gdk_color_free.
+ *
+ *--------------------------------------------------------------
+ */
+
+static GMemChunk *color_chunk;
+
+GdkColor*
+gdk_color_copy (GdkColor *color)
+{
+  GdkColor *new_color;
+  
+  g_return_val_if_fail (color != NULL, NULL);
+
+  if (color_chunk == NULL)
+    color_chunk = g_mem_chunk_new ("colors",
+                                  sizeof (GdkColor),
+                                  4096,
+                                  G_ALLOC_AND_FREE);
+
+  new_color = g_chunk_new (GdkColor, color_chunk);
+  *new_color = *color;
+  return new_color;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_color_free
+ *
+ *   Free a color structure obtained from gdk_color_copy.  Do not use
+ *   with other color structures.
+ *
+ * Arguments:
+ *   "color" is the color struct to free.
+ *
+ *-------------------------------------------------------------- */
+
+void
+gdk_color_free (GdkColor *color)
+{
+  g_assert (color_chunk != NULL);
+  g_return_if_fail (color != NULL);
+
+  g_mem_chunk_free (color_chunk, color);
+}
+
+gint
+gdk_color_white (GdkColormap *colormap,
+                GdkColor    *color)
+{
+  gint return_val;
+
+  g_return_val_if_fail (colormap != NULL, FALSE);
+
+  if (color)
+    {
+      color->red = 65535;
+      color->green = 65535;
+      color->blue = 65535;
+
+      return_val = gdk_color_alloc (colormap, color);
+    }
+  else
+    return_val = FALSE;
+
+  return return_val;
+}
+
+gint
+gdk_color_black (GdkColormap *colormap,
+                GdkColor    *color)
+{
+  gint return_val;
+
+  g_return_val_if_fail (colormap != NULL, FALSE);
+
+  if (color)
+    {
+      color->red = 0;
+      color->green = 0;
+      color->blue = 0;
+
+      return_val = gdk_color_alloc (colormap, color);
+    }
+  else
+    return_val = FALSE;
+
+  return return_val;
+}
+
+gboolean
+gdk_color_parse (const gchar *spec,
+                GdkColor *color)
+{
+  Colormap xcolormap;
+  XColor xcolor;
+  gboolean return_val;
+
+  g_return_val_if_fail (spec != NULL, FALSE);
+  g_return_val_if_fail (color != NULL, FALSE);
+
+  xcolormap = DefaultColormap ();
+
+  if (parse_color (xcolormap, spec, color))
+    return_val = TRUE;
+  else
+    return_val = FALSE;
+
+  return return_val;
+}
+
+/********************
+ * Color allocation *
+ ********************/
+
+/* Try to allocate a single color using alloc_color. If it succeeds,
+ * cache the result in our colormap, and store in ret.
+ */
+static gboolean 
+gdk_colormap_alloc1 (GdkColormap *colormap,
+                    GdkColor    *color,
+                    GdkColor    *ret)
+{
+  GdkColormapPrivate *private;
+  XColor xcolor;
+
+  private = (GdkColormapPrivate*) colormap;
+
+  xcolor.peRed = color->red >> 8;
+  xcolor.peGreen = color->green >> 8;
+  xcolor.peBlue = color->blue >> 8;
+
+  if (alloc_color (private->xcolormap, &xcolor, &ret->pixel))
+    {
+      ret->red = (xcolor.peRed * 65535) / 255;
+      ret->green = (xcolor.peGreen * 65535) / 255;;
+      ret->blue = (xcolor.peBlue * 65535) / 255;
+      
+      if ((guint) ret->pixel < colormap->size)
+       {
+         if (private->info[ret->pixel].ref_count) /* got a duplicate */
+           {
+             /* XXX */
+           }
+         else
+           {
+             colormap->colors[ret->pixel] = *color;
+             private->info[ret->pixel].ref_count = 1;
+
+             g_hash_table_insert (private->hash,
+                                  &colormap->colors[ret->pixel],
+                                  &colormap->colors[ret->pixel]);
+           }
+       }
+      return TRUE;
+    }
+  else
+    {
+      return FALSE;
+    }
+}
+
+static gint
+gdk_colormap_alloc_colors_writeable (GdkColormap *colormap,
+                                    GdkColor    *colors,
+                                    gint         ncolors,
+                                    gboolean     writeable,
+                                    gboolean     best_match,
+                                    gboolean    *success)
+{
+  GdkColormapPrivate *private;
+  gulong *pixels;
+  Status status;
+  gint i, index;
+
+  private = (GdkColormapPrivate*) colormap;
+
+  if (private->private_val)
+    {
+      index = 0;
+      for (i=0; i<ncolors; i++)
+       {
+         while ((index < colormap->size) && (private->info[index].ref_count != 0))
+           index++;
+         
+         if (index < colormap->size)
+           {
+             colors[i].pixel = index;
+             success[i] = TRUE;
+             private->info[index].ref_count++;
+             private->info[i].flags |= GDK_COLOR_WRITEABLE;
+           }
+         else
+           break;
+       }
+      return i;
+    }
+  else
+    {
+      pixels = g_new (gulong, ncolors);
+
+      /* Allocation of a writeable color cells */
+      status =  alloc_color_cells (private->xcolormap, FALSE, NULL,
+                                  0, pixels, ncolors);
+      if (status)
+       {
+         for (i=0; i<ncolors; i++)
+           {
+             colors[i].pixel = pixels[i];
+             private->info[pixels[i]].ref_count++;
+             private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE;
+           }
+       }
+      
+      g_free (pixels);
+
+      return status ? ncolors : 0; 
+    }
+}
+
+static gint
+gdk_colormap_alloc_colors_private (GdkColormap *colormap,
+                                  GdkColor    *colors,
+                                  gint         ncolors,
+                                  gboolean     writeable,
+                                  gboolean     best_match,
+                                  gboolean    *success)
+{
+  GdkColormapPrivate *private;
+  gint i, index;
+  XColor *store = g_new (XColor, ncolors);
+  gint nstore = 0;
+  gint nremaining = 0;
+  
+  private = (GdkColormapPrivate*) colormap;
+  index = -1;
+
+  /* First, store the colors we have room for */
+
+  index = 0;
+  for (i=0; i<ncolors; i++)
+    {
+      if (!success[i])
+       {
+         while ((index < colormap->size) && (private->info[index].ref_count != 0))
+           index++;
+
+         if (index < colormap->size)
+           {
+             store[nstore].peRed = colors[i].red >> 8;
+             store[nstore].peBlue = colors[i].blue >> 8;
+             store[nstore].peGreen = colors[i].green >> 8;
+             nstore++;
+
+             success[i] = TRUE;
+
+             colors[i].pixel = index;
+             private->info[index].ref_count++;
+           }
+         else
+           nremaining++;
+       }
+    }
+  
+  if (SetPaletteEntries (private->xcolormap->palette,
+                        0, nstore, store) == 0)
+    g_warning ("gdk_colormap_alloc_colors_private: SetPaletteEntries failed");
+  private->xcolormap->stale = TRUE;
+
+  g_free (store);
+
+  if (nremaining > 0 && best_match)
+    {
+      /* Get best matches for remaining colors */
+
+      gchar *available = g_new (gchar, colormap->size);
+      for (i = 0; i < colormap->size; i++)
+       available[i] = TRUE;
+
+      for (i=0; i<ncolors; i++)
+       {
+         if (!success[i])
+           {
+             index = gdk_colormap_match_color (colormap, 
+                                               &colors[i], 
+                                               available);
+             if (index != -1)
+               {
+                 colors[i] = colormap->colors[index];
+                 private->info[index].ref_count++;
+                 success[i] = TRUE;
+                 nremaining--;
+               }
+           }
+       }
+      g_free (available);
+    }
+
+  return (ncolors - nremaining);
+}
+
+static gint
+gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
+                                 GdkColor    *colors,
+                                 gint         ncolors,
+                                 gboolean     writeable,
+                                 gboolean     best_match,
+                                 gboolean    *success)
+{
+  GdkColormapPrivate *private;
+  gint i, index;
+  gint nremaining = 0;
+  gint nfailed = 0;
+
+  private = (GdkColormapPrivate*) colormap;
+  index = -1;
+
+  for (i=0; i<ncolors; i++)
+    {
+      if (!success[i])
+       {
+         if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
+           success[i] = TRUE;
+         else
+           nremaining++;
+       }
+    }
+
+
+  if (nremaining > 0 && best_match)
+    {
+      gchar *available = g_new (gchar, colormap->size);
+      for (i = 0; i < colormap->size; i++)
+       available[i] = ((private->info[i].ref_count == 0) ||
+                       !(private->info[i].flags && GDK_COLOR_WRITEABLE));
+      gdk_colormap_sync (colormap, FALSE);
+      
+      while (nremaining > 0)
+       {
+         for (i=0; i<ncolors; i++)
+           {
+             if (!success[i])
+               {
+                 index = gdk_colormap_match_color (colormap, &colors[i], available);
+                 if (index != -1)
+                   {
+                     if (private->info[index].ref_count)
+                       {
+                         private->info[index].ref_count++;
+                         colors[i] = colormap->colors[index];
+                         success[i] = TRUE;
+                         nremaining--;
+                       }
+                     else
+                       {
+                         if (gdk_colormap_alloc1 (colormap, 
+                                                  &colormap->colors[index],
+                                                  &colors[i]))
+                           {
+                             success[i] = TRUE;
+                             nremaining--;
+                             break;
+                           }
+                         else
+                           {
+                             available[index] = FALSE;
+                           }
+                       }
+                   }
+                 else
+                   {
+                     nfailed++;
+                     nremaining--;
+                     success[i] = 2; /* flag as permanent failure */
+                   }
+               }
+           }
+       }
+      g_free (available);
+    }
+
+  /* Change back the values we flagged as permanent failures */
+  if (nfailed > 0)
+    {
+      for (i=0; i<ncolors; i++)
+       if (success[i] == 2)
+         success[i] = FALSE;
+      nremaining = nfailed;
+    }
+  
+  return (ncolors - nremaining);
+}
+
+static gint
+gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
+                                      GdkColor    *colors,
+                                      gint         ncolors,
+                                      gboolean     writeable,
+                                      gboolean     best_match,
+                                      gboolean    *success)
+{
+  GdkColormapPrivate *private;
+  GdkColor *lookup_color;
+  gint i;
+  gint nremaining = 0;
+
+  private = (GdkColormapPrivate*) colormap;
+
+  /* Check for an exact match among previously allocated colors */
+
+  for (i=0; i<ncolors; i++)
+    {
+      if (!success[i])
+       {
+         lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
+         if (lookup_color)
+           {
+             private->info[lookup_color->pixel].ref_count++;
+             colors[i].pixel = lookup_color->pixel;
+             success[i] = TRUE;
+           }
+         else
+           nremaining++;
+       }
+    }
+
+  /* If that failed, we try to allocate a new color, or approxmiate
+   * with what we can get if best_match is TRUE.
+   */
+  if (nremaining > 0)
+    {
+      if (private->private_val)
+       return gdk_colormap_alloc_colors_private (colormap, colors, ncolors, writeable, best_match, success);
+      else
+       return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
+    }
+  else
+    return 0;
+}
+
+gint
+gdk_colormap_alloc_colors (GdkColormap *colormap,
+                          GdkColor    *colors,
+                          gint         ncolors,
+                          gboolean     writeable,
+                          gboolean     best_match,
+                          gboolean    *success)
+{
+  GdkColormapPrivate *private;
+  GdkVisual *visual;
+  gint i;
+  gint nremaining = 0;
+  XColor xcolor;
+
+  g_return_val_if_fail (colormap != NULL, FALSE);
+  g_return_val_if_fail (colors != NULL, FALSE);
+
+  private = (GdkColormapPrivate*) colormap;
+
+  for (i=0; i<ncolors; i++)
+    {
+      success[i] = FALSE;
+    }
+
+  switch (private->visual->type)
+    {
+    case GDK_VISUAL_PSEUDO_COLOR:
+    case GDK_VISUAL_GRAYSCALE:
+      if (writeable)
+       return gdk_colormap_alloc_colors_writeable (colormap, colors, ncolors,
+                                                   writeable, best_match, success);
+      else
+       return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors,
+                                                   writeable, best_match, success);
+      break;
+
+    case GDK_VISUAL_TRUE_COLOR:
+      visual = private->visual;
+
+      for (i=0; i<ncolors; i++)
+       {
+         colors[i].pixel = (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) +
+                            ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) +
+                            ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift));
+         success[i] = TRUE;
+       }
+      break;
+
+    case GDK_VISUAL_STATIC_GRAY:
+    case GDK_VISUAL_STATIC_COLOR:
+      for (i=0; i<ncolors; i++)
+       {
+         xcolor.peRed = colors[i].red >> 8;
+         xcolor.peGreen = colors[i].green >> 8;
+         xcolor.peBlue = colors[i].blue >> 8;
+         if (alloc_color (private->xcolormap, &xcolor, &colors[i].pixel))
+           success[i] = TRUE;
+         else
+           nremaining++;
+       }
+      break;
+    }
+  return nremaining;
+}
+
+gboolean
+gdk_colormap_alloc_color (GdkColormap *colormap,
+                         GdkColor    *color,
+                         gboolean     writeable,
+                         gboolean     best_match)
+{
+  gboolean success;
+
+  GDK_NOTE (MISC, g_print ("gdk_colormap_alloc_color: (%.04x,%.04x,%.04x)",
+                          color->red, color->green, color->blue));
+
+  gdk_colormap_alloc_colors (colormap, color, 1, writeable, best_match,
+                            &success);
+  GDK_NOTE (MISC, g_print (" -> %.08x\n", color->pixel));
+
+  return success;
+}
+
+/* This is almost identical to gdk_colors_free.
+ * Keep them in sync!
+ */
+void
+gdk_colormap_free_colors (GdkColormap *colormap,
+                         GdkColor    *colors,
+                         gint         ncolors)
+{
+  GdkColormapPrivate *private;
+  gulong *pixels;
+  gint npixels = 0;
+  gint i;
+
+  g_return_if_fail (colormap != NULL);
+  g_return_if_fail (colors != NULL);
+
+  private = (GdkColormapPrivate*) colormap;
+
+  if ((private->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
+      (private->visual->type != GDK_VISUAL_GRAYSCALE))
+    return;
+
+  pixels = g_new (gulong, ncolors);
+
+  for (i=0; i<ncolors; i++)
+    {
+      gulong pixel = colors[i].pixel;
+      
+      if (private->info[pixel].ref_count)
+       {
+         private->info[pixel].ref_count--;
+
+         if (private->info[pixel].ref_count == 0)
+           {
+             pixels[npixels++] = pixel;
+             if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
+               g_hash_table_remove (private->hash, &colors[i]);
+             private->info[pixel].flags = 0;
+           }
+       }
+    }
+  if (npixels)
+    XFreeColors (private->xcolormap, pixels, npixels, 0);
+  g_free (pixels);
+}
+
+gboolean
+gdk_color_alloc (GdkColormap *colormap,
+                GdkColor    *color)
+{
+  gboolean success;
+
+  GDK_NOTE (MISC, g_print ("gdk_color_alloc: (%.04x,%.04x,%.04x)",
+                          color->red, color->green, color->blue));
+
+  gdk_colormap_alloc_colors (colormap, color, 1, FALSE, TRUE, &success);
+
+  GDK_NOTE (MISC, g_print (" -> %.08x\n", color->pixel));
+
+  return success;
+}
+
+gboolean
+gdk_color_change (GdkColormap *colormap,
+                 GdkColor    *color)
+{
+  GdkColormapPrivate *private;
+  XColor xcolor;
+
+  g_return_val_if_fail (colormap != NULL, FALSE);
+  g_return_val_if_fail (color != NULL, FALSE);
+
+  private = (GdkColormapPrivate*) colormap;
+
+  xcolor.peRed = color->red >> 8;
+  xcolor.peGreen = color->green >> 8;
+  xcolor.peBlue = color->blue >> 8;
+
+  if (SetPaletteEntries (private->xcolormap->palette,
+                        color->pixel, 1, &xcolor) == 0)
+    g_warning ("gdk_color_change: SetPaletteEntries failed");
+  private->xcolormap->stale = TRUE;
+
+  return TRUE;
+}
+
+guint
+gdk_color_hash (const GdkColor *colora)
+{
+  return ((colora->red) +
+         (colora->green << 11) +
+         (colora->blue << 22) +
+         (colora->blue >> 6));
+}
+
+gint
+gdk_color_equal (const GdkColor *colora,
+                const GdkColor *colorb)
+{
+  g_return_val_if_fail (colora != NULL, FALSE);
+  g_return_val_if_fail (colorb != NULL, FALSE);
+
+  return ((colora->red == colorb->red) &&
+         (colora->green == colorb->green) &&
+         (colora->blue == colorb->blue));
+}
+
+static gint
+gdk_colormap_match_color (GdkColormap *cmap,
+                         GdkColor    *color,
+                         const gchar *available)
+{
+  GdkColor *colors;
+  guint sum, max;
+  gint rdiff, gdiff, bdiff;
+  gint i, index;
+
+  g_return_val_if_fail (cmap != NULL, 0);
+  g_return_val_if_fail (color != NULL, 0);
+
+  colors = cmap->colors;
+  max = 3 * (65536);
+  index = -1;
+
+  for (i = 0; i < cmap->size; i++)
+    {
+      if ((!available) || (available && available[i]))
+       {
+         rdiff = (color->red - colors[i].red);
+         gdiff = (color->green - colors[i].green);
+         bdiff = (color->blue - colors[i].blue);
+
+         sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
+
+         if (sum < max)
+           {
+             index = i;
+             max = sum;
+           }
+       }
+    }
+
+  return index;
+}
+
+GdkColormap*
+gdk_colormap_lookup (Colormap xcolormap)
+{
+  GdkColormap *cmap;
+
+  if (!colormap_hash)
+    return NULL;
+
+  cmap = g_hash_table_lookup (colormap_hash, &xcolormap);
+  return cmap;
+}
+
+static void
+gdk_colormap_add (GdkColormap *cmap)
+{
+  GdkColormapPrivate *private;
+
+  if (!colormap_hash)
+    colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
+                                     (GCompareFunc) gdk_colormap_cmp);
+
+  private = (GdkColormapPrivate*) cmap;
+
+  g_hash_table_insert (colormap_hash, &private->xcolormap, cmap);
+}
+
+static void
+gdk_colormap_remove (GdkColormap *cmap)
+{
+  GdkColormapPrivate *private;
+
+  if (!colormap_hash)
+    colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash,
+                                     (GCompareFunc) gdk_colormap_cmp);
+
+  private = (GdkColormapPrivate*) cmap;
+
+  g_hash_table_remove (colormap_hash, &private->xcolormap);
+}
+
+static guint
+gdk_colormap_hash (Colormap *cmap)
+{
+  return (guint) *cmap;
+}
+
+static gint
+gdk_colormap_cmp (Colormap *a,
+                 Colormap *b)
+{
+  return (*a == *b);
+}
+
+char *
+gdk_color_to_string (GdkColor *color)
+{
+  static char buf[100];
+
+  sprintf (buf, "(%.04x,%.04x,%.04x): %.06x",
+          color->red, color->green, color->blue, color->pixel);
+
+  return buf;
+}
diff --git a/gdk/win32/gdkcursor-win32.c b/gdk/win32/gdkcursor-win32.c
new file mode 100644 (file)
index 0000000..8a293d1
--- /dev/null
@@ -0,0 +1,226 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gdk.h"
+#include "gdkprivate.h"
+
+static const struct { const char *name; int type; } cursors[] = {
+  { "x_cursor", 0 },
+  { "arrow", 2 },
+  { "based_arrow_down", 4 },
+  { "based_arrow_up", 6 },
+  { "boat", 8 },
+  { "bogosity", 10 },
+  { "bottom_left_corner", 12 },
+  { "bottom_right_corner", 14 },
+  { "bottom_side", 16 },
+  { "bottom_tee", 18 },
+  { "box_spiral", 20 },
+  { "center_ptr", 22 },
+  { "circle", 24 },
+  { "clock", 26 },
+  { "coffee_mug", 28 },
+  { "cross", 30 },
+  { "cross_reverse", 32 },
+  { "crosshair", 34 },
+  { "diamond_cross", 36 },
+  { "dot", 38 },
+  { "dotbox", 40 },
+  { "double_arrow", 42 },
+  { "draft_large", 44 },
+  { "draft_small", 46 },
+  { "draped_box", 48 },
+  { "exchange", 50 },
+  { "fleur", 52 },
+  { "gobbler", 54 },
+  { "gumby", 56 },
+  { "hand1", 58 },
+  { "hand2", 60 },
+  { "heart", 62 },
+  { "icon", 64 },
+  { "iron_cross", 66 },
+  { "left_ptr", 68 },
+  { "left_side", 70 },
+  { "left_tee", 72 },
+  { "leftbutton", 74 },
+  { "ll_angle", 76 },
+  { "lr_angle", 78 },
+  { "man", 80 },
+  { "middlebutton", 82 },
+  { "mouse", 84 },
+  { "pencil", 86 },
+  { "pirate", 88 },
+  { "plus", 90 },
+  { "question_arrow", 92 },
+  { "right_ptr", 94 },
+  { "right_side", 96 },
+  { "right_tee", 98 },
+  { "rightbutton", 100 },
+  { "rtl_logo", 102 },
+  { "sailboat", 104 },
+  { "sb_down_arrow", 106 },
+  { "sb_h_double_arrow", 108 },
+  { "sb_left_arrow", 110 },
+  { "sb_right_arrow", 112 },
+  { "sb_up_arrow", 114 },
+  { "sb_v_double_arrow", 116 },
+  { "shuttle", 118 },
+  { "sizing", 120 },
+  { "spider", 122 },
+  { "spraycan", 124 },
+  { "star", 126 },
+  { "target", 128 },
+  { "tcross", 130 },
+  { "top_left_arrow", 132 },
+  { "top_left_corner", 134 },
+  { "top_right_corner", 136 },
+  { "top_side", 138 },
+  { "top_tee", 140 },
+  { "trek", 142 },
+  { "ul_angle", 144 },
+  { "umbrella", 146 },
+  { "ur_angle", 148 },
+  { "watch", 150 },
+  { "xterm", 152 },
+  { NULL, 0 }
+};  
+
+GdkCursor*
+gdk_cursor_new (GdkCursorType cursor_type)
+{
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+  HCURSOR xcursor;
+
+  int i;
+
+  for (i = 0; cursors[i].name != NULL && cursors[i].type != cursor_type; i++)
+    ;
+  if (cursors[i].name != NULL)
+    {
+      xcursor = LoadCursor (gdk_DLLInstance, cursors[i].name);
+      if (xcursor == NULL)
+       g_warning ("gdk_cursor_new: LoadCursor failed");
+      GDK_NOTE (MISC, g_print ("gdk_cursor_new: %#x %d\n",
+                              xcursor, cursor_type));
+    }
+  else
+    {
+      g_warning ("gdk_cursor_new: no cursor %d found",
+                cursor_type);
+      xcursor = NULL;
+    }
+
+  private = g_new (GdkCursorPrivate, 1);
+  private->xcursor = xcursor;
+  cursor = (GdkCursor*) private;
+  cursor->type = cursor_type;
+
+  return cursor;
+}
+
+GdkCursor*
+gdk_cursor_new_from_pixmap (GdkPixmap *source, GdkPixmap *mask, GdkColor *fg, GdkColor *bg, gint x, gint y)
+{
+#if 0                          /* I don't understand cursors, sigh */
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+  GdkPixmap *s2;
+  GdkPixmapPrivate *source_private, *mask_private;
+  GdkPixmapPrivate *s2_private;
+  GdkGC *gc;
+  ICONINFO iconinfo;
+  HCURSOR xcursor;
+  HBITMAP invmask;
+  HDC hdc1, hdc2;
+  HGDIOBJ oldbm1, oldbm2;
+  
+  source_private = (GdkPixmapPrivate *) source;
+  mask_private   = (GdkPixmapPrivate *) mask;
+
+  s2 = gdk_pixmap_new (source, source_private->width, source_private->height, 1);
+  gc = gdk_gc_new (s2);
+  gdk_gc_set_foreground (gc, fg);
+  gdk_gc_set_background (gc, bg);
+  gdk_draw_pixmap (s2, gc, source, 0, 0, 0, 0,
+                  source_private->width, source_private->height);
+  gdk_gc_unref (gc);
+  
+  iconinfo.fIcon = FALSE;
+  iconinfo.xHotspot = x;
+  iconinfo.yHotspot = y;
+#if 1
+  invmask = CreateBitmap (mask_private->width, mask_private->height, 1, 1, NULL);
+  hdc1 = CreateCompatibleDC (gdk_DC);
+  oldbm1 = SelectObject (hdc1, invmask);
+  hdc2 = CreateCompatibleDC (gdk_DC);
+  oldbm2 = SelectObject (hdc2, mask_private->xwindow);
+  BitBlt (hdc1, 0, 0, mask_private->width, mask_private->height, hdc2, 0, 0, NOTSRCCOPY);
+  SelectObject (hdc2, oldbm2);
+  DeleteDC (hdc2);
+  SelectObject (hdc1, oldbm1);
+  DeleteDC (hdc1);
+  iconinfo.hbmMask = invmask;
+#else
+  iconinfo.hbmMask = mask_private->xwindow;;
+#endif
+  iconinfo.hbmColor = ((GdkPixmapPrivate *) s2)->xwindow;
+
+  if ((xcursor = CreateIconIndirect (&iconinfo)) == NULL)
+    {
+      g_warning ("gdk_cursor_new_from_private: CreateIconIndirect failed");
+      gdk_pixmap_unref (s2);
+      return gdk_cursor_new (GDK_PIRATE);
+    }
+
+  GDK_NOTE (MISC,
+           g_print ("gdk_cursor_new_from_private: %#x (%dx%d) %#x (%dx%d) = %#x\n",
+                    source_private->xwindow,
+                    source_private->width, source_private->height,
+                    mask_private->xwindow,
+                    mask_private->width, mask_private->height,
+                    xcursor));
+
+  gdk_pixmap_unref (s2);
+  private = g_new (GdkCursorPrivate, 1);
+  private->xcursor = xcursor;
+  cursor = (GdkCursor*) private;
+  cursor->type = GDK_CURSOR_IS_PIXMAP;
+
+  return cursor;
+#else  /* Just return some cursor ;-) */
+  return gdk_cursor_new (GDK_PIRATE);
+#endif
+}
+
+void
+gdk_cursor_destroy (GdkCursor *cursor)
+{
+  GdkCursorPrivate *private;
+
+  g_return_if_fail (cursor != NULL);
+  private = (GdkCursorPrivate *) cursor;
+
+  if (cursor->type == GDK_CURSOR_IS_PIXMAP)
+    DestroyIcon (private->xcursor);
+
+  g_free (private);
+}
diff --git a/gdk/win32/gdkcursor.c b/gdk/win32/gdkcursor.c
new file mode 100644 (file)
index 0000000..8a293d1
--- /dev/null
@@ -0,0 +1,226 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gdk.h"
+#include "gdkprivate.h"
+
+static const struct { const char *name; int type; } cursors[] = {
+  { "x_cursor", 0 },
+  { "arrow", 2 },
+  { "based_arrow_down", 4 },
+  { "based_arrow_up", 6 },
+  { "boat", 8 },
+  { "bogosity", 10 },
+  { "bottom_left_corner", 12 },
+  { "bottom_right_corner", 14 },
+  { "bottom_side", 16 },
+  { "bottom_tee", 18 },
+  { "box_spiral", 20 },
+  { "center_ptr", 22 },
+  { "circle", 24 },
+  { "clock", 26 },
+  { "coffee_mug", 28 },
+  { "cross", 30 },
+  { "cross_reverse", 32 },
+  { "crosshair", 34 },
+  { "diamond_cross", 36 },
+  { "dot", 38 },
+  { "dotbox", 40 },
+  { "double_arrow", 42 },
+  { "draft_large", 44 },
+  { "draft_small", 46 },
+  { "draped_box", 48 },
+  { "exchange", 50 },
+  { "fleur", 52 },
+  { "gobbler", 54 },
+  { "gumby", 56 },
+  { "hand1", 58 },
+  { "hand2", 60 },
+  { "heart", 62 },
+  { "icon", 64 },
+  { "iron_cross", 66 },
+  { "left_ptr", 68 },
+  { "left_side", 70 },
+  { "left_tee", 72 },
+  { "leftbutton", 74 },
+  { "ll_angle", 76 },
+  { "lr_angle", 78 },
+  { "man", 80 },
+  { "middlebutton", 82 },
+  { "mouse", 84 },
+  { "pencil", 86 },
+  { "pirate", 88 },
+  { "plus", 90 },
+  { "question_arrow", 92 },
+  { "right_ptr", 94 },
+  { "right_side", 96 },
+  { "right_tee", 98 },
+  { "rightbutton", 100 },
+  { "rtl_logo", 102 },
+  { "sailboat", 104 },
+  { "sb_down_arrow", 106 },
+  { "sb_h_double_arrow", 108 },
+  { "sb_left_arrow", 110 },
+  { "sb_right_arrow", 112 },
+  { "sb_up_arrow", 114 },
+  { "sb_v_double_arrow", 116 },
+  { "shuttle", 118 },
+  { "sizing", 120 },
+  { "spider", 122 },
+  { "spraycan", 124 },
+  { "star", 126 },
+  { "target", 128 },
+  { "tcross", 130 },
+  { "top_left_arrow", 132 },
+  { "top_left_corner", 134 },
+  { "top_right_corner", 136 },
+  { "top_side", 138 },
+  { "top_tee", 140 },
+  { "trek", 142 },
+  { "ul_angle", 144 },
+  { "umbrella", 146 },
+  { "ur_angle", 148 },
+  { "watch", 150 },
+  { "xterm", 152 },
+  { NULL, 0 }
+};  
+
+GdkCursor*
+gdk_cursor_new (GdkCursorType cursor_type)
+{
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+  HCURSOR xcursor;
+
+  int i;
+
+  for (i = 0; cursors[i].name != NULL && cursors[i].type != cursor_type; i++)
+    ;
+  if (cursors[i].name != NULL)
+    {
+      xcursor = LoadCursor (gdk_DLLInstance, cursors[i].name);
+      if (xcursor == NULL)
+       g_warning ("gdk_cursor_new: LoadCursor failed");
+      GDK_NOTE (MISC, g_print ("gdk_cursor_new: %#x %d\n",
+                              xcursor, cursor_type));
+    }
+  else
+    {
+      g_warning ("gdk_cursor_new: no cursor %d found",
+                cursor_type);
+      xcursor = NULL;
+    }
+
+  private = g_new (GdkCursorPrivate, 1);
+  private->xcursor = xcursor;
+  cursor = (GdkCursor*) private;
+  cursor->type = cursor_type;
+
+  return cursor;
+}
+
+GdkCursor*
+gdk_cursor_new_from_pixmap (GdkPixmap *source, GdkPixmap *mask, GdkColor *fg, GdkColor *bg, gint x, gint y)
+{
+#if 0                          /* I don't understand cursors, sigh */
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+  GdkPixmap *s2;
+  GdkPixmapPrivate *source_private, *mask_private;
+  GdkPixmapPrivate *s2_private;
+  GdkGC *gc;
+  ICONINFO iconinfo;
+  HCURSOR xcursor;
+  HBITMAP invmask;
+  HDC hdc1, hdc2;
+  HGDIOBJ oldbm1, oldbm2;
+  
+  source_private = (GdkPixmapPrivate *) source;
+  mask_private   = (GdkPixmapPrivate *) mask;
+
+  s2 = gdk_pixmap_new (source, source_private->width, source_private->height, 1);
+  gc = gdk_gc_new (s2);
+  gdk_gc_set_foreground (gc, fg);
+  gdk_gc_set_background (gc, bg);
+  gdk_draw_pixmap (s2, gc, source, 0, 0, 0, 0,
+                  source_private->width, source_private->height);
+  gdk_gc_unref (gc);
+  
+  iconinfo.fIcon = FALSE;
+  iconinfo.xHotspot = x;
+  iconinfo.yHotspot = y;
+#if 1
+  invmask = CreateBitmap (mask_private->width, mask_private->height, 1, 1, NULL);
+  hdc1 = CreateCompatibleDC (gdk_DC);
+  oldbm1 = SelectObject (hdc1, invmask);
+  hdc2 = CreateCompatibleDC (gdk_DC);
+  oldbm2 = SelectObject (hdc2, mask_private->xwindow);
+  BitBlt (hdc1, 0, 0, mask_private->width, mask_private->height, hdc2, 0, 0, NOTSRCCOPY);
+  SelectObject (hdc2, oldbm2);
+  DeleteDC (hdc2);
+  SelectObject (hdc1, oldbm1);
+  DeleteDC (hdc1);
+  iconinfo.hbmMask = invmask;
+#else
+  iconinfo.hbmMask = mask_private->xwindow;;
+#endif
+  iconinfo.hbmColor = ((GdkPixmapPrivate *) s2)->xwindow;
+
+  if ((xcursor = CreateIconIndirect (&iconinfo)) == NULL)
+    {
+      g_warning ("gdk_cursor_new_from_private: CreateIconIndirect failed");
+      gdk_pixmap_unref (s2);
+      return gdk_cursor_new (GDK_PIRATE);
+    }
+
+  GDK_NOTE (MISC,
+           g_print ("gdk_cursor_new_from_private: %#x (%dx%d) %#x (%dx%d) = %#x\n",
+                    source_private->xwindow,
+                    source_private->width, source_private->height,
+                    mask_private->xwindow,
+                    mask_private->width, mask_private->height,
+                    xcursor));
+
+  gdk_pixmap_unref (s2);
+  private = g_new (GdkCursorPrivate, 1);
+  private->xcursor = xcursor;
+  cursor = (GdkCursor*) private;
+  cursor->type = GDK_CURSOR_IS_PIXMAP;
+
+  return cursor;
+#else  /* Just return some cursor ;-) */
+  return gdk_cursor_new (GDK_PIRATE);
+#endif
+}
+
+void
+gdk_cursor_destroy (GdkCursor *cursor)
+{
+  GdkCursorPrivate *private;
+
+  g_return_if_fail (cursor != NULL);
+  private = (GdkCursorPrivate *) cursor;
+
+  if (cursor->type == GDK_CURSOR_IS_PIXMAP)
+    DestroyIcon (private->xcursor);
+
+  g_free (private);
+}
diff --git a/gdk/win32/gdkdnd-win32.c b/gdk/win32/gdkdnd-win32.c
new file mode 100644 (file)
index 0000000..3cd3716
--- /dev/null
@@ -0,0 +1,863 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-1999 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#define INITGUID
+
+#include <string.h>
+#include "gdk.h"
+#include "gdkx.h"
+#include "gdk/gdkprivate.h"
+#include <ole2.h>
+#include <shlobj.h>
+#include <shlguid.h>
+
+typedef struct _GdkDragContextPrivate GdkDragContextPrivate;
+
+typedef enum {
+  GDK_DRAG_STATUS_DRAG,
+  GDK_DRAG_STATUS_MOTION_WAIT,
+  GDK_DRAG_STATUS_ACTION_WAIT,
+  GDK_DRAG_STATUS_DROP
+} GtkDragStatus;
+
+typedef enum {
+  GDK_DRAG_SOURCE,
+  GDK_DRAG_TARGET
+} GdkDragKind;
+
+#ifdef OLE2_DND
+
+HRESULT STDMETHODCALLTYPE
+  m_query_interface_target (IDropTarget __RPC_FAR *This,
+                           /* [in] */ REFIID riid,
+                           /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
+
+ULONG STDMETHODCALLTYPE
+  m_add_ref_target (IDropTarget __RPC_FAR *This);
+
+ULONG STDMETHODCALLTYPE
+  m_release_target (IDropTarget __RPC_FAR *This);
+
+HRESULT STDMETHODCALLTYPE 
+  m_drag_enter (IDropTarget __RPC_FAR *This,
+               /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
+               /* [in] */ DWORD grfKeyState,
+               /* [in] */ POINTL pt,
+               /* [out][in] */ DWORD __RPC_FAR *pdwEffect);
+
+HRESULT STDMETHODCALLTYPE
+  m_drag_over (IDropTarget __RPC_FAR *This,
+              /* [in] */ DWORD grfKeyState,
+              /* [in] */ POINTL pt,
+              /* [out][in] */ DWORD __RPC_FAR *pdwEffect);
+
+HRESULT STDMETHODCALLTYPE
+  m_drag_leave (IDropTarget __RPC_FAR *This);
+
+HRESULT STDMETHODCALLTYPE
+  m_drop (IDropTarget __RPC_FAR *This,
+         /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
+         /* [in] */ DWORD grfKeyState,
+         /* [in] */ POINTL pt,
+         /* [out][in] */ DWORD __RPC_FAR *pdwEffect);
+
+HRESULT STDMETHODCALLTYPE
+  m_query_interface_source (IDropSource __RPC_FAR *This,
+                           /* [in] */ REFIID riid,
+                           /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
+
+ULONG STDMETHODCALLTYPE
+  m_add_ref_source (IDropSource __RPC_FAR *This);
+
+ULONG STDMETHODCALLTYPE
+  m_release_source (IDropSource __RPC_FAR *This);
+
+HRESULT STDMETHODCALLTYPE
+  m_query_continue_drag (IDropSource __RPC_FAR *This,
+                        /* [in] */ BOOL fEscapePressed,
+                        /* [in] */ DWORD grfKeyState);
+HRESULT STDMETHODCALLTYPE
+  m_give_feedback (IDropSource __RPC_FAR *This,
+                  /* [in] */ DWORD dwEffect);
+
+#endif /* OLE2_DND */
+
+/* Structure that holds information about a drag in progress.
+ * this is used on both source and destination sides.
+ */
+struct _GdkDragContextPrivate {
+  GdkDragContext context;
+
+  guint   ref_count;
+
+  guint16 last_x;              /* Coordinates from last event */
+  guint16 last_y;
+  HWND  dest_xid;
+  guint drag_status;           /* Current status of drag */
+};
+
+GdkDragContext *current_dest_drag = NULL;
+
+/* Drag Contexts */
+
+static GList *contexts;
+
+GdkDragContext *
+gdk_drag_context_new        (void)
+{
+  GdkDragContextPrivate *result;
+
+  result = g_new0 (GdkDragContextPrivate, 1);
+
+  result->ref_count = 1;
+
+  contexts = g_list_prepend (contexts, result);
+
+  return (GdkDragContext *)result;
+}
+
+#if OLE2_DND
+
+typedef struct {
+  IDropTarget idt;
+  GdkDragContext *context;
+} target_drag_context;
+
+typedef struct {
+  IDropSource ids;
+  GdkDragContext *context;
+} source_drag_context;
+
+HRESULT STDMETHODCALLTYPE
+m_query_interface_target (IDropTarget __RPC_FAR *This,
+                         /* [in] */ REFIID riid,
+                         /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
+{
+  GDK_NOTE (DND, g_print ("m_query_interface_target\n"));
+
+  *ppvObject = NULL;
+
+  g_print ("riid = %.08x-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x",
+          ((gulong *) riid)[0],
+          ((gushort *) riid)[2],
+          ((gushort *) riid)[3],
+          ((guchar *) riid)[8],
+          ((guchar *) riid)[9],
+          ((guchar *) riid)[10],
+          ((guchar *) riid)[11],
+          ((guchar *) riid)[12],
+          ((guchar *) riid)[13],
+          ((guchar *) riid)[14],
+          ((guchar *) riid)[15]);
+  if (IsEqualGUID (riid, &IID_IUnknown))
+    {
+      m_add_ref_target (This);
+      *ppvObject = This;
+      g_print ("...IUnknown\n");
+      return S_OK;
+    }
+  else if (IsEqualGUID (riid, &IID_IDropTarget))
+    {
+      m_add_ref_target (This);
+      *ppvObject = This;
+      g_print ("...IDropTarget\n");
+      return S_OK;
+    }
+  else
+    {
+      g_print ("...Huh?\n");
+      return E_NOINTERFACE;
+    }
+}
+
+ULONG STDMETHODCALLTYPE
+m_add_ref_target (IDropTarget __RPC_FAR *This)
+{
+  target_drag_context *ctx = (target_drag_context *) This;
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
+
+  GDK_NOTE (DND, g_print ("m_add_ref_target\n"));
+  gdk_drag_context_ref (ctx->context);
+  
+  return private->ref_count;
+}
+
+ULONG STDMETHODCALLTYPE
+m_release_target (IDropTarget __RPC_FAR *This)
+{
+  target_drag_context *ctx = (target_drag_context *) This;
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
+
+  GDK_NOTE (DND, g_print ("m_release_target\n"));
+  gdk_drag_context_unref (ctx->context);
+
+  if (private->ref_count == 1)
+    {
+      gdk_drag_context_unref (ctx->context);
+      return 0;
+    }
+  else
+    return private->ref_count - 1;
+}
+
+HRESULT STDMETHODCALLTYPE 
+m_drag_enter (IDropTarget __RPC_FAR *This,
+             /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
+             /* [in] */ DWORD grfKeyState,
+             /* [in] */ POINTL pt,
+             /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
+{
+  GDK_NOTE (DND, g_print ("m_drag_enter\n"));
+  return E_UNEXPECTED;
+}
+
+HRESULT STDMETHODCALLTYPE
+m_drag_over (IDropTarget __RPC_FAR *This,
+            /* [in] */ DWORD grfKeyState,
+            /* [in] */ POINTL pt,
+            /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
+{
+  GDK_NOTE (DND, g_print ("m_drag_over\n"));
+  return E_UNEXPECTED;
+}
+
+HRESULT STDMETHODCALLTYPE
+m_drag_leave (IDropTarget __RPC_FAR *This)
+{
+  GDK_NOTE (DND, g_print ("m_drag_leave\n"));
+  return E_UNEXPECTED;
+}
+
+HRESULT STDMETHODCALLTYPE
+m_drop (IDropTarget __RPC_FAR *This,
+       /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
+       /* [in] */ DWORD grfKeyState,
+       /* [in] */ POINTL pt,
+       /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
+{
+  GDK_NOTE (DND, g_print ("m_drop\n"));
+  return E_UNEXPECTED;
+}
+HRESULT STDMETHODCALLTYPE
+m_query_interface_source (IDropSource __RPC_FAR *This,
+                         /* [in] */ REFIID riid,
+                         /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
+{
+  GDK_NOTE (DND, g_print ("m_query_interface_source\n"));
+
+  *ppvObject = NULL;
+
+  g_print ("riid = %.02x%.02x%.02x%.02x-%.02x%.02x-%.02x%.02x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x",
+          ((guchar *) riid)[0],
+          ((guchar *) riid)[1],
+          ((guchar *) riid)[2],
+          ((guchar *) riid)[3],
+          ((guchar *) riid)[4],
+          ((guchar *) riid)[5],
+          ((guchar *) riid)[6],
+          ((guchar *) riid)[7],
+          ((guchar *) riid)[8],
+          ((guchar *) riid)[9],
+          ((guchar *) riid)[10],
+          ((guchar *) riid)[11],
+          ((guchar *) riid)[12],
+          ((guchar *) riid)[13],
+          ((guchar *) riid)[14],
+          ((guchar *) riid)[15]);
+  if (IsEqualGUID (riid, &IID_IUnknown))
+    {
+      m_add_ref_source (This);
+      *ppvObject = This;
+      g_print ("...IUnknown\n");
+      return S_OK;
+    }
+  else if (IsEqualGUID (riid, &IID_IDropSource))
+    {
+      m_add_ref_source (This);
+      *ppvObject = This;
+      g_print ("...IDropSource\n");
+      return S_OK;
+    }
+  else
+    {
+      g_print ("...Huh?\n");
+      return E_NOINTERFACE;
+    }
+}
+
+ULONG STDMETHODCALLTYPE
+m_add_ref_source (IDropSource __RPC_FAR *This)
+{
+  source_drag_context *ctx = (source_drag_context *) This;
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
+
+  GDK_NOTE (DND, g_print ("m_add_ref_source\n"));
+  gdk_drag_context_ref (ctx->context);
+  
+  return private->ref_count;
+}
+
+ULONG STDMETHODCALLTYPE
+m_release_source (IDropSource __RPC_FAR *This)
+{
+  source_drag_context *ctx = (source_drag_context *) This;
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
+
+  GDK_NOTE (DND, g_print ("m_release_source\n"));
+  gdk_drag_context_unref (ctx->context);
+
+  if (private->ref_count == 1)
+    {
+      gdk_drag_context_unref (ctx->context);
+      return 0;
+    }
+  else
+    return private->ref_count - 1;
+}
+
+HRESULT STDMETHODCALLTYPE
+m_query_continue_drag (IDropSource __RPC_FAR *This,
+                      /* [in] */ BOOL fEscapePressed,
+                      /* [in] */ DWORD grfKeyState)
+{
+  GDK_NOTE (DND, g_print ("m_query_continue_drag\n"));
+  return E_UNEXPECTED;
+}
+
+HRESULT STDMETHODCALLTYPE
+m_give_feedback (IDropSource __RPC_FAR *This,
+                /* [in] */ DWORD dwEffect)
+{
+  GDK_NOTE (DND, g_print ("m_give_feedback\n"));
+  return E_UNEXPECTED;
+}
+
+static IDropTargetVtbl idt_vtbl = {
+  m_query_interface_target,
+  m_add_ref_target,
+  m_release_target,
+  m_drag_enter,
+  m_drag_over,
+  m_drag_leave,
+  m_drop
+};
+
+static IDropSourceVtbl ids_vtbl = {
+  m_query_interface_source,
+  m_add_ref_source,
+  m_release_source,
+  m_query_continue_drag,
+  m_give_feedback
+};
+
+target_drag_context *
+target_context_new (void)
+{
+  target_drag_context *result;
+
+  result = g_new0 (target_drag_context, 1);
+
+  result->idt.lpVtbl = &idt_vtbl;
+
+  result->context = gdk_drag_context_new ();
+
+  return result;
+}
+
+source_drag_context *
+source_context_new (void)
+{
+  source_drag_context *result;
+
+  result = g_new0 (source_drag_context, 1);
+
+  result->ids.lpVtbl = &ids_vtbl;
+
+  result->context = gdk_drag_context_new ();
+
+  return result;
+}
+
+#endif /* OLE2_DND */
+
+void            
+gdk_drag_context_ref (GdkDragContext *context)
+{
+  g_return_if_fail (context != NULL);
+
+  ((GdkDragContextPrivate *)context)->ref_count++;
+}
+
+void            
+gdk_drag_context_unref (GdkDragContext *context)
+{
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+  
+  g_return_if_fail (context != NULL);
+
+  private->ref_count--;
+
+  GDK_NOTE (DND, g_print ("gdk_drag_context_unref: %d%s\n",
+                         private->ref_count,
+                         (private->ref_count == 0 ? " freeing" : "")));
+
+  if (private->ref_count == 0)
+    {
+      g_dataset_destroy (private);
+      
+      g_list_free (context->targets);
+
+      if (context->source_window)
+       gdk_window_unref (context->source_window);
+
+      if (context->dest_window)
+       gdk_window_unref (context->dest_window);
+
+      contexts = g_list_remove (contexts, private);
+      g_free (private);
+    }
+}
+
+#if 0
+
+static GdkDragContext *
+gdk_drag_context_find (gboolean is_source,
+                      HWND     source_xid,
+                      HWND     dest_xid)
+{
+  GList *tmp_list = contexts;
+  GdkDragContext *context;
+
+  while (tmp_list)
+    {
+      context = (GdkDragContext *)tmp_list->data;
+
+      if ((!context->is_source == !is_source) &&
+         ((source_xid == None) || (context->source_window &&
+           (GDK_WINDOW_XWINDOW (context->source_window) == source_xid))) &&
+         ((dest_xid == None) || (context->dest_window &&
+           (GDK_WINDOW_XWINDOW (context->dest_window) == dest_xid))))
+       return context;
+      
+      tmp_list = tmp_list->next;
+    }
+
+  return NULL;
+}
+
+#endif
+
+/* From MS Knowledge Base article Q130698 */
+
+/* resolve_link() fills the filename and path buffer
+ * with relevant information
+ * hWnd         - calling app's window handle.
+ *
+ * lpszLinkName - name of the link file passed into the function.
+ *
+ * lpszPath     - the buffer that will receive the file pathname.
+ */
+
+static HRESULT 
+resolve_link(HWND hWnd,
+            LPCTSTR lpszLinkName,
+            LPSTR lpszPath,
+            LPSTR lpszDescription)
+{
+  HRESULT hres;
+  IShellLink *psl;
+  WIN32_FIND_DATA wfd;
+
+  /* Assume Failure to start with: */
+  *lpszPath = 0;
+  if (lpszDescription)
+    *lpszDescription = 0;
+
+  /* Call CoCreateInstance to obtain the IShellLink interface
+   * pointer. This call fails if CoInitialize is not called, so it is
+   * assumed that CoInitialize has been called.
+   */
+
+  hres = CoCreateInstance (&CLSID_ShellLink,
+                          NULL,
+                          CLSCTX_INPROC_SERVER,
+                          &IID_IShellLink,
+                          (LPVOID *)&psl);
+  if (SUCCEEDED (hres))
+   {
+     IPersistFile *ppf;
+     
+     /* The IShellLink interface supports the IPersistFile
+      * interface. Get an interface pointer to it.
+      */
+     hres = psl->lpVtbl->QueryInterface (psl,
+                                        &IID_IPersistFile,
+                                        (LPVOID *) &ppf);
+     if (SUCCEEDED (hres))
+       {
+         WORD wsz[MAX_PATH];
+
+        /* Convert the given link name string to wide character string. */
+         MultiByteToWideChar (CP_ACP, 0,
+                             lpszLinkName,
+                             -1, wsz, MAX_PATH);
+        /* Load the file. */
+         hres = ppf->lpVtbl->Load (ppf, wsz, STGM_READ);
+         if (SUCCEEDED (hres))
+          {
+            /* Resolve the link by calling the Resolve()
+             * interface function.
+             */
+            hres = psl->lpVtbl->Resolve(psl,  hWnd,
+                                        SLR_ANY_MATCH |
+                                        SLR_NO_UI);
+            if (SUCCEEDED (hres))
+              {
+                hres = psl->lpVtbl->GetPath (psl, lpszPath,
+                                             MAX_PATH,
+                                             (WIN32_FIND_DATA*)&wfd,
+                                             0);
+
+                if (SUCCEEDED (hres) && lpszDescription != NULL)
+                  {
+                    hres = psl->lpVtbl->GetDescription (psl,
+                                                        lpszDescription,
+                                                        MAX_PATH );
+
+                    if (!SUCCEEDED (hres))
+                      return FALSE;
+                  }
+              }
+          }
+         ppf->lpVtbl->Release (ppf);
+       }
+     psl->lpVtbl->Release (psl);
+   }
+  return SUCCEEDED (hres);
+}
+
+static GdkFilterReturn
+gdk_dropfiles_filter (GdkXEvent *xev,
+                     GdkEvent  *event,
+                     gpointer   data)
+{
+  GdkDragContext *context;
+  GdkDragContextPrivate *private;
+  static GdkAtom text_uri_list_atom = GDK_NONE;
+  GString *result;
+  MSG *msg = (MSG *) xev;
+  HANDLE hdrop;
+  POINT pt;
+  gint nfiles, i, k;
+  guchar fileName[MAX_PATH], linkedFile[MAX_PATH];
+  
+  if (text_uri_list_atom == GDK_NONE)
+    text_uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE);
+
+  if (msg->message == WM_DROPFILES)
+    {
+      GDK_NOTE (DND, g_print ("WM_DROPFILES: %#x\n", msg->hwnd));
+
+      context = gdk_drag_context_new ();
+      private = (GdkDragContextPrivate *) context;
+      context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
+      context->is_source = FALSE;
+      context->source_window = (GdkWindow *) &gdk_root_parent;
+      context->dest_window = event->any.window;
+      gdk_window_ref (context->dest_window);
+      /* WM_DROPFILES drops are always file names */
+      context->targets =
+       g_list_append (NULL, GUINT_TO_POINTER (text_uri_list_atom));
+      current_dest_drag = context;
+
+      event->dnd.type = GDK_DROP_START;
+      event->dnd.context = current_dest_drag;
+      gdk_drag_context_ref (current_dest_drag);
+      
+      hdrop = (HANDLE) msg->wParam;
+      DragQueryPoint (hdrop, &pt);
+      ClientToScreen (msg->hwnd, &pt);
+
+      event->dnd.x_root = pt.x;
+      event->dnd.y_root = pt.y;
+      event->dnd.time = msg->time;
+
+      nfiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
+
+      result = g_string_new (NULL);
+      for (i = 0; i < nfiles; i++)
+       {
+         g_string_append (result, "file:");
+         DragQueryFile (hdrop, i, fileName, MAX_PATH);
+
+         /* Resolve shortcuts */
+         if (resolve_link (msg->hwnd, fileName, linkedFile, NULL))
+           {
+             g_string_append (result, linkedFile);
+             GDK_NOTE (DND, g_print ("...%s link to %s\n",
+                                     fileName, linkedFile));
+           }
+         else
+           {
+             g_string_append (result, fileName);
+             GDK_NOTE (DND, g_print ("...%s\n", fileName));
+           }
+         g_string_append (result, "\015\012");
+       }
+      gdk_sel_prop_store ((GdkWindow *) &gdk_root_parent,
+                         text_uri_list_atom, 8, result->str, result->len + 1);
+
+      DragFinish (hdrop);
+      
+      return GDK_FILTER_TRANSLATE;
+    }
+  else
+    return GDK_FILTER_CONTINUE;
+}
+                    
+
+/*************************************************************
+ ************************** Public API ***********************
+ *************************************************************/
+
+void
+gdk_dnd_init (void)
+{
+  HRESULT hres;
+
+  hres = OleInitialize (NULL);
+
+  if (! SUCCEEDED (hres))
+    g_error ("OleInitialize failed");
+}                    
+
+void
+gdk_dnd_exit (void)
+{
+  OleUninitialize ();
+}
+
+/* Source side */
+
+static void
+gdk_drag_do_leave (GdkDragContext *context, guint32 time)
+{
+  if (context->dest_window)
+    {
+      GDK_NOTE (DND, g_print ("gdk_drag_do_leave\n"));
+      gdk_window_unref (context->dest_window);
+      context->dest_window = NULL;
+    }
+}
+
+GdkDragContext * 
+gdk_drag_begin (GdkWindow     *window,
+               GList         *targets)
+{
+  GList *tmp_list;
+  GdkDragContext *new_context;
+  
+  g_return_val_if_fail (window != NULL, NULL);
+
+  GDK_NOTE (DND, g_print ("gdk_drag_begin\n"));
+
+  new_context = gdk_drag_context_new ();
+  new_context->is_source = TRUE;
+  new_context->source_window = window;
+  gdk_window_ref (window);
+
+  tmp_list = g_list_last (targets);
+  new_context->targets = NULL;
+  while (tmp_list)
+    {
+      new_context->targets = g_list_prepend (new_context->targets,
+                                            tmp_list->data);
+      tmp_list = tmp_list->prev;
+    }
+
+  new_context->actions = 0;
+
+  return new_context;
+}
+
+guint32
+gdk_drag_get_protocol (guint32          xid,
+                      GdkDragProtocol *protocol)
+{
+  /* This isn't used */
+  return 0;
+}
+
+void
+gdk_drag_find_window (GdkDragContext  *context,
+                     GdkWindow       *drag_window,
+                     gint             x_root,
+                     gint             y_root,
+                     GdkWindow      **dest_window,
+                     GdkDragProtocol *protocol)
+{
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+  GdkWindowPrivate *drag_window_private = (GdkWindowPrivate *) drag_window;
+  HWND recipient;
+  POINT pt;
+
+  GDK_NOTE (DND, g_print ("gdk_drag_find_window: %#x +%d+%d\n",
+                         (drag_window ? drag_window_private->xwindow : 0),
+                         x_root, y_root));
+
+  pt.x = x_root;
+  pt.y = y_root;
+  recipient = WindowFromPoint (pt);
+  if (recipient == NULL)
+    *dest_window = NULL;
+  else
+    {
+      *dest_window = gdk_window_lookup (recipient);
+      if (*dest_window)
+       gdk_window_ref (*dest_window);
+      *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
+    }
+}
+
+gboolean        
+gdk_drag_motion (GdkDragContext *context,
+                GdkWindow      *dest_window,
+                GdkDragProtocol protocol,
+                gint            x_root, 
+                gint            y_root,
+                GdkDragAction   suggested_action,
+                GdkDragAction   possible_actions,
+                guint32         time)
+{
+  return FALSE;
+}
+
+void
+gdk_drag_drop (GdkDragContext *context,
+              guint32         time)
+{
+  g_return_if_fail (context != NULL);
+
+  g_warning ("gdk_drag_drop: not implemented\n");
+}
+
+void
+gdk_drag_abort (GdkDragContext *context,
+               guint32         time)
+{
+  g_return_if_fail (context != NULL);
+
+  gdk_drag_do_leave (context, time);
+}
+
+/* Destination side */
+
+void             
+gdk_drag_status (GdkDragContext   *context,
+                GdkDragAction     action,
+                guint32           time)
+{
+  GDK_NOTE (DND, g_print ("gdk_drag_status\n"));
+}
+
+void 
+gdk_drop_reply (GdkDragContext   *context,
+               gboolean          ok,
+               guint32           time)
+{
+}
+
+void             
+gdk_drop_finish (GdkDragContext   *context,
+                gboolean          success,
+                guint32           time)
+{
+}
+
+
+void            
+gdk_window_register_dnd (GdkWindow      *window)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *) window;
+#if OLE2_DND
+  target_drag_context *context;
+  HRESULT hres;
+#endif
+
+  g_return_if_fail (window != NULL);
+
+  GDK_NOTE (DND, g_print ("gdk_window_register_dnd: %#x\n", private->xwindow));
+
+  /* We always claim to accept dropped files, but in fact we might not,
+   * of course. This function is called in such a way that it cannot know
+   * whether the window (widget) in question actually accepts files
+   * (in gtk, data of type text/uri-list) or not.
+   */
+  gdk_window_add_filter (window, gdk_dropfiles_filter, NULL);
+  DragAcceptFiles (private->xwindow, TRUE);
+
+#if OLE2_DND
+  /* Register for OLE2 d&d */
+  context = target_context_new ();
+  hres = CoLockObjectExternal ((IUnknown *) &context->idt, TRUE, FALSE);
+  if (!SUCCEEDED (hres))
+    g_warning ("gdk_window_register_dnd: CoLockObjectExternal failed");
+  else
+    {
+      hres = RegisterDragDrop (private->xwindow, &context->idt);
+      if (hres == DRAGDROP_E_ALREADYREGISTERED)
+       {
+         g_print ("DRAGDROP_E_ALREADYREGISTERED\n");
+         CoLockObjectExternal ((IUnknown *) &context->idt, FALSE, FALSE);
+       }
+      else if (!SUCCEEDED (hres))
+       g_warning ("gdk_window_register_dnd: RegisterDragDrop failed");
+    }
+#endif
+}
+
+/*************************************************************
+ * gdk_drag_get_selection:
+ *     Returns the selection atom for the current source window
+ *   arguments:
+ *     
+ *   results:
+ *************************************************************/
+
+GdkAtom       
+gdk_drag_get_selection (GdkDragContext *context)
+{
+  if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES)
+    return gdk_win32_dropfiles_atom;
+  else if (context->protocol == GDK_DRAG_PROTO_OLE2)
+    return gdk_ole2_dnd_atom;
+  else
+    return GDK_NONE;
+}
diff --git a/gdk/win32/gdkdnd.c b/gdk/win32/gdkdnd.c
new file mode 100644 (file)
index 0000000..3cd3716
--- /dev/null
@@ -0,0 +1,863 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-1999 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#define INITGUID
+
+#include <string.h>
+#include "gdk.h"
+#include "gdkx.h"
+#include "gdk/gdkprivate.h"
+#include <ole2.h>
+#include <shlobj.h>
+#include <shlguid.h>
+
+typedef struct _GdkDragContextPrivate GdkDragContextPrivate;
+
+typedef enum {
+  GDK_DRAG_STATUS_DRAG,
+  GDK_DRAG_STATUS_MOTION_WAIT,
+  GDK_DRAG_STATUS_ACTION_WAIT,
+  GDK_DRAG_STATUS_DROP
+} GtkDragStatus;
+
+typedef enum {
+  GDK_DRAG_SOURCE,
+  GDK_DRAG_TARGET
+} GdkDragKind;
+
+#ifdef OLE2_DND
+
+HRESULT STDMETHODCALLTYPE
+  m_query_interface_target (IDropTarget __RPC_FAR *This,
+                           /* [in] */ REFIID riid,
+                           /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
+
+ULONG STDMETHODCALLTYPE
+  m_add_ref_target (IDropTarget __RPC_FAR *This);
+
+ULONG STDMETHODCALLTYPE
+  m_release_target (IDropTarget __RPC_FAR *This);
+
+HRESULT STDMETHODCALLTYPE 
+  m_drag_enter (IDropTarget __RPC_FAR *This,
+               /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
+               /* [in] */ DWORD grfKeyState,
+               /* [in] */ POINTL pt,
+               /* [out][in] */ DWORD __RPC_FAR *pdwEffect);
+
+HRESULT STDMETHODCALLTYPE
+  m_drag_over (IDropTarget __RPC_FAR *This,
+              /* [in] */ DWORD grfKeyState,
+              /* [in] */ POINTL pt,
+              /* [out][in] */ DWORD __RPC_FAR *pdwEffect);
+
+HRESULT STDMETHODCALLTYPE
+  m_drag_leave (IDropTarget __RPC_FAR *This);
+
+HRESULT STDMETHODCALLTYPE
+  m_drop (IDropTarget __RPC_FAR *This,
+         /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
+         /* [in] */ DWORD grfKeyState,
+         /* [in] */ POINTL pt,
+         /* [out][in] */ DWORD __RPC_FAR *pdwEffect);
+
+HRESULT STDMETHODCALLTYPE
+  m_query_interface_source (IDropSource __RPC_FAR *This,
+                           /* [in] */ REFIID riid,
+                           /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
+
+ULONG STDMETHODCALLTYPE
+  m_add_ref_source (IDropSource __RPC_FAR *This);
+
+ULONG STDMETHODCALLTYPE
+  m_release_source (IDropSource __RPC_FAR *This);
+
+HRESULT STDMETHODCALLTYPE
+  m_query_continue_drag (IDropSource __RPC_FAR *This,
+                        /* [in] */ BOOL fEscapePressed,
+                        /* [in] */ DWORD grfKeyState);
+HRESULT STDMETHODCALLTYPE
+  m_give_feedback (IDropSource __RPC_FAR *This,
+                  /* [in] */ DWORD dwEffect);
+
+#endif /* OLE2_DND */
+
+/* Structure that holds information about a drag in progress.
+ * this is used on both source and destination sides.
+ */
+struct _GdkDragContextPrivate {
+  GdkDragContext context;
+
+  guint   ref_count;
+
+  guint16 last_x;              /* Coordinates from last event */
+  guint16 last_y;
+  HWND  dest_xid;
+  guint drag_status;           /* Current status of drag */
+};
+
+GdkDragContext *current_dest_drag = NULL;
+
+/* Drag Contexts */
+
+static GList *contexts;
+
+GdkDragContext *
+gdk_drag_context_new        (void)
+{
+  GdkDragContextPrivate *result;
+
+  result = g_new0 (GdkDragContextPrivate, 1);
+
+  result->ref_count = 1;
+
+  contexts = g_list_prepend (contexts, result);
+
+  return (GdkDragContext *)result;
+}
+
+#if OLE2_DND
+
+typedef struct {
+  IDropTarget idt;
+  GdkDragContext *context;
+} target_drag_context;
+
+typedef struct {
+  IDropSource ids;
+  GdkDragContext *context;
+} source_drag_context;
+
+HRESULT STDMETHODCALLTYPE
+m_query_interface_target (IDropTarget __RPC_FAR *This,
+                         /* [in] */ REFIID riid,
+                         /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
+{
+  GDK_NOTE (DND, g_print ("m_query_interface_target\n"));
+
+  *ppvObject = NULL;
+
+  g_print ("riid = %.08x-%.04x-%.04x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x",
+          ((gulong *) riid)[0],
+          ((gushort *) riid)[2],
+          ((gushort *) riid)[3],
+          ((guchar *) riid)[8],
+          ((guchar *) riid)[9],
+          ((guchar *) riid)[10],
+          ((guchar *) riid)[11],
+          ((guchar *) riid)[12],
+          ((guchar *) riid)[13],
+          ((guchar *) riid)[14],
+          ((guchar *) riid)[15]);
+  if (IsEqualGUID (riid, &IID_IUnknown))
+    {
+      m_add_ref_target (This);
+      *ppvObject = This;
+      g_print ("...IUnknown\n");
+      return S_OK;
+    }
+  else if (IsEqualGUID (riid, &IID_IDropTarget))
+    {
+      m_add_ref_target (This);
+      *ppvObject = This;
+      g_print ("...IDropTarget\n");
+      return S_OK;
+    }
+  else
+    {
+      g_print ("...Huh?\n");
+      return E_NOINTERFACE;
+    }
+}
+
+ULONG STDMETHODCALLTYPE
+m_add_ref_target (IDropTarget __RPC_FAR *This)
+{
+  target_drag_context *ctx = (target_drag_context *) This;
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
+
+  GDK_NOTE (DND, g_print ("m_add_ref_target\n"));
+  gdk_drag_context_ref (ctx->context);
+  
+  return private->ref_count;
+}
+
+ULONG STDMETHODCALLTYPE
+m_release_target (IDropTarget __RPC_FAR *This)
+{
+  target_drag_context *ctx = (target_drag_context *) This;
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
+
+  GDK_NOTE (DND, g_print ("m_release_target\n"));
+  gdk_drag_context_unref (ctx->context);
+
+  if (private->ref_count == 1)
+    {
+      gdk_drag_context_unref (ctx->context);
+      return 0;
+    }
+  else
+    return private->ref_count - 1;
+}
+
+HRESULT STDMETHODCALLTYPE 
+m_drag_enter (IDropTarget __RPC_FAR *This,
+             /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
+             /* [in] */ DWORD grfKeyState,
+             /* [in] */ POINTL pt,
+             /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
+{
+  GDK_NOTE (DND, g_print ("m_drag_enter\n"));
+  return E_UNEXPECTED;
+}
+
+HRESULT STDMETHODCALLTYPE
+m_drag_over (IDropTarget __RPC_FAR *This,
+            /* [in] */ DWORD grfKeyState,
+            /* [in] */ POINTL pt,
+            /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
+{
+  GDK_NOTE (DND, g_print ("m_drag_over\n"));
+  return E_UNEXPECTED;
+}
+
+HRESULT STDMETHODCALLTYPE
+m_drag_leave (IDropTarget __RPC_FAR *This)
+{
+  GDK_NOTE (DND, g_print ("m_drag_leave\n"));
+  return E_UNEXPECTED;
+}
+
+HRESULT STDMETHODCALLTYPE
+m_drop (IDropTarget __RPC_FAR *This,
+       /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
+       /* [in] */ DWORD grfKeyState,
+       /* [in] */ POINTL pt,
+       /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
+{
+  GDK_NOTE (DND, g_print ("m_drop\n"));
+  return E_UNEXPECTED;
+}
+HRESULT STDMETHODCALLTYPE
+m_query_interface_source (IDropSource __RPC_FAR *This,
+                         /* [in] */ REFIID riid,
+                         /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
+{
+  GDK_NOTE (DND, g_print ("m_query_interface_source\n"));
+
+  *ppvObject = NULL;
+
+  g_print ("riid = %.02x%.02x%.02x%.02x-%.02x%.02x-%.02x%.02x-%.02x%.02x-%.02x%.02x%.02x%.02x%.02x%.02x",
+          ((guchar *) riid)[0],
+          ((guchar *) riid)[1],
+          ((guchar *) riid)[2],
+          ((guchar *) riid)[3],
+          ((guchar *) riid)[4],
+          ((guchar *) riid)[5],
+          ((guchar *) riid)[6],
+          ((guchar *) riid)[7],
+          ((guchar *) riid)[8],
+          ((guchar *) riid)[9],
+          ((guchar *) riid)[10],
+          ((guchar *) riid)[11],
+          ((guchar *) riid)[12],
+          ((guchar *) riid)[13],
+          ((guchar *) riid)[14],
+          ((guchar *) riid)[15]);
+  if (IsEqualGUID (riid, &IID_IUnknown))
+    {
+      m_add_ref_source (This);
+      *ppvObject = This;
+      g_print ("...IUnknown\n");
+      return S_OK;
+    }
+  else if (IsEqualGUID (riid, &IID_IDropSource))
+    {
+      m_add_ref_source (This);
+      *ppvObject = This;
+      g_print ("...IDropSource\n");
+      return S_OK;
+    }
+  else
+    {
+      g_print ("...Huh?\n");
+      return E_NOINTERFACE;
+    }
+}
+
+ULONG STDMETHODCALLTYPE
+m_add_ref_source (IDropSource __RPC_FAR *This)
+{
+  source_drag_context *ctx = (source_drag_context *) This;
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
+
+  GDK_NOTE (DND, g_print ("m_add_ref_source\n"));
+  gdk_drag_context_ref (ctx->context);
+  
+  return private->ref_count;
+}
+
+ULONG STDMETHODCALLTYPE
+m_release_source (IDropSource __RPC_FAR *This)
+{
+  source_drag_context *ctx = (source_drag_context *) This;
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *) ctx->context;
+
+  GDK_NOTE (DND, g_print ("m_release_source\n"));
+  gdk_drag_context_unref (ctx->context);
+
+  if (private->ref_count == 1)
+    {
+      gdk_drag_context_unref (ctx->context);
+      return 0;
+    }
+  else
+    return private->ref_count - 1;
+}
+
+HRESULT STDMETHODCALLTYPE
+m_query_continue_drag (IDropSource __RPC_FAR *This,
+                      /* [in] */ BOOL fEscapePressed,
+                      /* [in] */ DWORD grfKeyState)
+{
+  GDK_NOTE (DND, g_print ("m_query_continue_drag\n"));
+  return E_UNEXPECTED;
+}
+
+HRESULT STDMETHODCALLTYPE
+m_give_feedback (IDropSource __RPC_FAR *This,
+                /* [in] */ DWORD dwEffect)
+{
+  GDK_NOTE (DND, g_print ("m_give_feedback\n"));
+  return E_UNEXPECTED;
+}
+
+static IDropTargetVtbl idt_vtbl = {
+  m_query_interface_target,
+  m_add_ref_target,
+  m_release_target,
+  m_drag_enter,
+  m_drag_over,
+  m_drag_leave,
+  m_drop
+};
+
+static IDropSourceVtbl ids_vtbl = {
+  m_query_interface_source,
+  m_add_ref_source,
+  m_release_source,
+  m_query_continue_drag,
+  m_give_feedback
+};
+
+target_drag_context *
+target_context_new (void)
+{
+  target_drag_context *result;
+
+  result = g_new0 (target_drag_context, 1);
+
+  result->idt.lpVtbl = &idt_vtbl;
+
+  result->context = gdk_drag_context_new ();
+
+  return result;
+}
+
+source_drag_context *
+source_context_new (void)
+{
+  source_drag_context *result;
+
+  result = g_new0 (source_drag_context, 1);
+
+  result->ids.lpVtbl = &ids_vtbl;
+
+  result->context = gdk_drag_context_new ();
+
+  return result;
+}
+
+#endif /* OLE2_DND */
+
+void            
+gdk_drag_context_ref (GdkDragContext *context)
+{
+  g_return_if_fail (context != NULL);
+
+  ((GdkDragContextPrivate *)context)->ref_count++;
+}
+
+void            
+gdk_drag_context_unref (GdkDragContext *context)
+{
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+  
+  g_return_if_fail (context != NULL);
+
+  private->ref_count--;
+
+  GDK_NOTE (DND, g_print ("gdk_drag_context_unref: %d%s\n",
+                         private->ref_count,
+                         (private->ref_count == 0 ? " freeing" : "")));
+
+  if (private->ref_count == 0)
+    {
+      g_dataset_destroy (private);
+      
+      g_list_free (context->targets);
+
+      if (context->source_window)
+       gdk_window_unref (context->source_window);
+
+      if (context->dest_window)
+       gdk_window_unref (context->dest_window);
+
+      contexts = g_list_remove (contexts, private);
+      g_free (private);
+    }
+}
+
+#if 0
+
+static GdkDragContext *
+gdk_drag_context_find (gboolean is_source,
+                      HWND     source_xid,
+                      HWND     dest_xid)
+{
+  GList *tmp_list = contexts;
+  GdkDragContext *context;
+
+  while (tmp_list)
+    {
+      context = (GdkDragContext *)tmp_list->data;
+
+      if ((!context->is_source == !is_source) &&
+         ((source_xid == None) || (context->source_window &&
+           (GDK_WINDOW_XWINDOW (context->source_window) == source_xid))) &&
+         ((dest_xid == None) || (context->dest_window &&
+           (GDK_WINDOW_XWINDOW (context->dest_window) == dest_xid))))
+       return context;
+      
+      tmp_list = tmp_list->next;
+    }
+
+  return NULL;
+}
+
+#endif
+
+/* From MS Knowledge Base article Q130698 */
+
+/* resolve_link() fills the filename and path buffer
+ * with relevant information
+ * hWnd         - calling app's window handle.
+ *
+ * lpszLinkName - name of the link file passed into the function.
+ *
+ * lpszPath     - the buffer that will receive the file pathname.
+ */
+
+static HRESULT 
+resolve_link(HWND hWnd,
+            LPCTSTR lpszLinkName,
+            LPSTR lpszPath,
+            LPSTR lpszDescription)
+{
+  HRESULT hres;
+  IShellLink *psl;
+  WIN32_FIND_DATA wfd;
+
+  /* Assume Failure to start with: */
+  *lpszPath = 0;
+  if (lpszDescription)
+    *lpszDescription = 0;
+
+  /* Call CoCreateInstance to obtain the IShellLink interface
+   * pointer. This call fails if CoInitialize is not called, so it is
+   * assumed that CoInitialize has been called.
+   */
+
+  hres = CoCreateInstance (&CLSID_ShellLink,
+                          NULL,
+                          CLSCTX_INPROC_SERVER,
+                          &IID_IShellLink,
+                          (LPVOID *)&psl);
+  if (SUCCEEDED (hres))
+   {
+     IPersistFile *ppf;
+     
+     /* The IShellLink interface supports the IPersistFile
+      * interface. Get an interface pointer to it.
+      */
+     hres = psl->lpVtbl->QueryInterface (psl,
+                                        &IID_IPersistFile,
+                                        (LPVOID *) &ppf);
+     if (SUCCEEDED (hres))
+       {
+         WORD wsz[MAX_PATH];
+
+        /* Convert the given link name string to wide character string. */
+         MultiByteToWideChar (CP_ACP, 0,
+                             lpszLinkName,
+                             -1, wsz, MAX_PATH);
+        /* Load the file. */
+         hres = ppf->lpVtbl->Load (ppf, wsz, STGM_READ);
+         if (SUCCEEDED (hres))
+          {
+            /* Resolve the link by calling the Resolve()
+             * interface function.
+             */
+            hres = psl->lpVtbl->Resolve(psl,  hWnd,
+                                        SLR_ANY_MATCH |
+                                        SLR_NO_UI);
+            if (SUCCEEDED (hres))
+              {
+                hres = psl->lpVtbl->GetPath (psl, lpszPath,
+                                             MAX_PATH,
+                                             (WIN32_FIND_DATA*)&wfd,
+                                             0);
+
+                if (SUCCEEDED (hres) && lpszDescription != NULL)
+                  {
+                    hres = psl->lpVtbl->GetDescription (psl,
+                                                        lpszDescription,
+                                                        MAX_PATH );
+
+                    if (!SUCCEEDED (hres))
+                      return FALSE;
+                  }
+              }
+          }
+         ppf->lpVtbl->Release (ppf);
+       }
+     psl->lpVtbl->Release (psl);
+   }
+  return SUCCEEDED (hres);
+}
+
+static GdkFilterReturn
+gdk_dropfiles_filter (GdkXEvent *xev,
+                     GdkEvent  *event,
+                     gpointer   data)
+{
+  GdkDragContext *context;
+  GdkDragContextPrivate *private;
+  static GdkAtom text_uri_list_atom = GDK_NONE;
+  GString *result;
+  MSG *msg = (MSG *) xev;
+  HANDLE hdrop;
+  POINT pt;
+  gint nfiles, i, k;
+  guchar fileName[MAX_PATH], linkedFile[MAX_PATH];
+  
+  if (text_uri_list_atom == GDK_NONE)
+    text_uri_list_atom = gdk_atom_intern ("text/uri-list", FALSE);
+
+  if (msg->message == WM_DROPFILES)
+    {
+      GDK_NOTE (DND, g_print ("WM_DROPFILES: %#x\n", msg->hwnd));
+
+      context = gdk_drag_context_new ();
+      private = (GdkDragContextPrivate *) context;
+      context->protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
+      context->is_source = FALSE;
+      context->source_window = (GdkWindow *) &gdk_root_parent;
+      context->dest_window = event->any.window;
+      gdk_window_ref (context->dest_window);
+      /* WM_DROPFILES drops are always file names */
+      context->targets =
+       g_list_append (NULL, GUINT_TO_POINTER (text_uri_list_atom));
+      current_dest_drag = context;
+
+      event->dnd.type = GDK_DROP_START;
+      event->dnd.context = current_dest_drag;
+      gdk_drag_context_ref (current_dest_drag);
+      
+      hdrop = (HANDLE) msg->wParam;
+      DragQueryPoint (hdrop, &pt);
+      ClientToScreen (msg->hwnd, &pt);
+
+      event->dnd.x_root = pt.x;
+      event->dnd.y_root = pt.y;
+      event->dnd.time = msg->time;
+
+      nfiles = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
+
+      result = g_string_new (NULL);
+      for (i = 0; i < nfiles; i++)
+       {
+         g_string_append (result, "file:");
+         DragQueryFile (hdrop, i, fileName, MAX_PATH);
+
+         /* Resolve shortcuts */
+         if (resolve_link (msg->hwnd, fileName, linkedFile, NULL))
+           {
+             g_string_append (result, linkedFile);
+             GDK_NOTE (DND, g_print ("...%s link to %s\n",
+                                     fileName, linkedFile));
+           }
+         else
+           {
+             g_string_append (result, fileName);
+             GDK_NOTE (DND, g_print ("...%s\n", fileName));
+           }
+         g_string_append (result, "\015\012");
+       }
+      gdk_sel_prop_store ((GdkWindow *) &gdk_root_parent,
+                         text_uri_list_atom, 8, result->str, result->len + 1);
+
+      DragFinish (hdrop);
+      
+      return GDK_FILTER_TRANSLATE;
+    }
+  else
+    return GDK_FILTER_CONTINUE;
+}
+                    
+
+/*************************************************************
+ ************************** Public API ***********************
+ *************************************************************/
+
+void
+gdk_dnd_init (void)
+{
+  HRESULT hres;
+
+  hres = OleInitialize (NULL);
+
+  if (! SUCCEEDED (hres))
+    g_error ("OleInitialize failed");
+}                    
+
+void
+gdk_dnd_exit (void)
+{
+  OleUninitialize ();
+}
+
+/* Source side */
+
+static void
+gdk_drag_do_leave (GdkDragContext *context, guint32 time)
+{
+  if (context->dest_window)
+    {
+      GDK_NOTE (DND, g_print ("gdk_drag_do_leave\n"));
+      gdk_window_unref (context->dest_window);
+      context->dest_window = NULL;
+    }
+}
+
+GdkDragContext * 
+gdk_drag_begin (GdkWindow     *window,
+               GList         *targets)
+{
+  GList *tmp_list;
+  GdkDragContext *new_context;
+  
+  g_return_val_if_fail (window != NULL, NULL);
+
+  GDK_NOTE (DND, g_print ("gdk_drag_begin\n"));
+
+  new_context = gdk_drag_context_new ();
+  new_context->is_source = TRUE;
+  new_context->source_window = window;
+  gdk_window_ref (window);
+
+  tmp_list = g_list_last (targets);
+  new_context->targets = NULL;
+  while (tmp_list)
+    {
+      new_context->targets = g_list_prepend (new_context->targets,
+                                            tmp_list->data);
+      tmp_list = tmp_list->prev;
+    }
+
+  new_context->actions = 0;
+
+  return new_context;
+}
+
+guint32
+gdk_drag_get_protocol (guint32          xid,
+                      GdkDragProtocol *protocol)
+{
+  /* This isn't used */
+  return 0;
+}
+
+void
+gdk_drag_find_window (GdkDragContext  *context,
+                     GdkWindow       *drag_window,
+                     gint             x_root,
+                     gint             y_root,
+                     GdkWindow      **dest_window,
+                     GdkDragProtocol *protocol)
+{
+  GdkDragContextPrivate *private = (GdkDragContextPrivate *)context;
+  GdkWindowPrivate *drag_window_private = (GdkWindowPrivate *) drag_window;
+  HWND recipient;
+  POINT pt;
+
+  GDK_NOTE (DND, g_print ("gdk_drag_find_window: %#x +%d+%d\n",
+                         (drag_window ? drag_window_private->xwindow : 0),
+                         x_root, y_root));
+
+  pt.x = x_root;
+  pt.y = y_root;
+  recipient = WindowFromPoint (pt);
+  if (recipient == NULL)
+    *dest_window = NULL;
+  else
+    {
+      *dest_window = gdk_window_lookup (recipient);
+      if (*dest_window)
+       gdk_window_ref (*dest_window);
+      *protocol = GDK_DRAG_PROTO_WIN32_DROPFILES;
+    }
+}
+
+gboolean        
+gdk_drag_motion (GdkDragContext *context,
+                GdkWindow      *dest_window,
+                GdkDragProtocol protocol,
+                gint            x_root, 
+                gint            y_root,
+                GdkDragAction   suggested_action,
+                GdkDragAction   possible_actions,
+                guint32         time)
+{
+  return FALSE;
+}
+
+void
+gdk_drag_drop (GdkDragContext *context,
+              guint32         time)
+{
+  g_return_if_fail (context != NULL);
+
+  g_warning ("gdk_drag_drop: not implemented\n");
+}
+
+void
+gdk_drag_abort (GdkDragContext *context,
+               guint32         time)
+{
+  g_return_if_fail (context != NULL);
+
+  gdk_drag_do_leave (context, time);
+}
+
+/* Destination side */
+
+void             
+gdk_drag_status (GdkDragContext   *context,
+                GdkDragAction     action,
+                guint32           time)
+{
+  GDK_NOTE (DND, g_print ("gdk_drag_status\n"));
+}
+
+void 
+gdk_drop_reply (GdkDragContext   *context,
+               gboolean          ok,
+               guint32           time)
+{
+}
+
+void             
+gdk_drop_finish (GdkDragContext   *context,
+                gboolean          success,
+                guint32           time)
+{
+}
+
+
+void            
+gdk_window_register_dnd (GdkWindow      *window)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *) window;
+#if OLE2_DND
+  target_drag_context *context;
+  HRESULT hres;
+#endif
+
+  g_return_if_fail (window != NULL);
+
+  GDK_NOTE (DND, g_print ("gdk_window_register_dnd: %#x\n", private->xwindow));
+
+  /* We always claim to accept dropped files, but in fact we might not,
+   * of course. This function is called in such a way that it cannot know
+   * whether the window (widget) in question actually accepts files
+   * (in gtk, data of type text/uri-list) or not.
+   */
+  gdk_window_add_filter (window, gdk_dropfiles_filter, NULL);
+  DragAcceptFiles (private->xwindow, TRUE);
+
+#if OLE2_DND
+  /* Register for OLE2 d&d */
+  context = target_context_new ();
+  hres = CoLockObjectExternal ((IUnknown *) &context->idt, TRUE, FALSE);
+  if (!SUCCEEDED (hres))
+    g_warning ("gdk_window_register_dnd: CoLockObjectExternal failed");
+  else
+    {
+      hres = RegisterDragDrop (private->xwindow, &context->idt);
+      if (hres == DRAGDROP_E_ALREADYREGISTERED)
+       {
+         g_print ("DRAGDROP_E_ALREADYREGISTERED\n");
+         CoLockObjectExternal ((IUnknown *) &context->idt, FALSE, FALSE);
+       }
+      else if (!SUCCEEDED (hres))
+       g_warning ("gdk_window_register_dnd: RegisterDragDrop failed");
+    }
+#endif
+}
+
+/*************************************************************
+ * gdk_drag_get_selection:
+ *     Returns the selection atom for the current source window
+ *   arguments:
+ *     
+ *   results:
+ *************************************************************/
+
+GdkAtom       
+gdk_drag_get_selection (GdkDragContext *context)
+{
+  if (context->protocol == GDK_DRAG_PROTO_WIN32_DROPFILES)
+    return gdk_win32_dropfiles_atom;
+  else if (context->protocol == GDK_DRAG_PROTO_OLE2)
+    return gdk_ole2_dnd_atom;
+  else
+    return GDK_NONE;
+}
diff --git a/gdk/win32/gdkdraw.c b/gdk/win32/gdkdraw.c
new file mode 100644 (file)
index 0000000..700bdb5
--- /dev/null
@@ -0,0 +1,655 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include "gdk.h"
+#include "gdkprivate.h"
+
+#ifndef M_TWOPI
+#define M_TWOPI         (2.0 * 3.14159265358979323846)
+#endif
+
+void
+gdk_draw_point (GdkDrawable *drawable,
+                GdkGC       *gc,
+                gint         x,
+                gint         y)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  HBRUSH hbr;
+  RECT rect;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+  hbr = GetCurrentObject (hdc, OBJ_BRUSH);
+  /* We use FillRect because SetPixel wants the COLORREF directly,
+   * and doesn't use the current brush, which is what we want.
+   */
+  rect.left = x;
+  rect.top = y;
+  rect.right = rect.left + 1;
+  rect.bottom = rect.top + 1;
+  FillRect (hdc, &rect, hbr);
+  
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_line (GdkDrawable *drawable,
+              GdkGC       *gc,
+              gint         x1,
+              gint         y1,
+              gint         x2,
+              gint         y2)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+    
+  GDK_NOTE (MISC, g_print ("gdk_draw_line: %#x (%d) +%d+%d..+%d+%d\n",
+                          drawable_private->xwindow, gc_private,
+                          x1, y1, x2, y2));
+  
+  MoveToEx (hdc, x1, y1, NULL);
+  if (!LineTo (hdc, x2, y2))
+    g_warning ("gdk_draw_line: LineTo #1 failed");
+  /* LineTo doesn't draw the last point, so if we have a pen width of 1,
+   * we draw the end pixel separately... With wider pens it hopefully
+   * doesn't matter?
+   */
+  if (gc_private->pen_width == 1)
+    if (!LineTo (hdc, x2 + 1, y2))
+      g_warning ("gdk_draw_line: LineTo #2 failed");
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_rectangle (GdkDrawable *drawable,
+                   GdkGC       *gc,
+                   gint         filled,
+                   gint         x,
+                   gint         y,
+                   gint         width,
+                   gint         height)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  LOGBRUSH lb;
+  HPEN hpen;
+  HBRUSH hbr;
+  HGDIOBJ oldpen, oldbrush;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  if (width == -1)
+    width = drawable_private->width;
+  if (height == -1)
+    height = drawable_private->height;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+
+  GDK_NOTE (MISC, g_print ("gdk_draw_rectangle: %#x (%d) %s%dx%d@+%d+%d\n",
+                          drawable_private->xwindow,
+                          gc_private,
+                          (filled ? "fill " : ""),
+                          width, height, x, y));
+    
+#if 0
+  {
+    HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH);
+    HPEN hpen = GetCurrentObject (hdc, OBJ_PEN);
+    LOGBRUSH lbr;
+    LOGPEN lpen;
+    GetObject (hbr, sizeof (lbr), &lbr);
+    GetObject (hpen, sizeof (lpen), &lpen);
+    
+    g_print ("current brush: style = %s, color = 0x%.08x\n",
+            (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"),
+            lbr.lbColor);
+    g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n",
+            (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"),
+            lpen.lopnWidth,
+            lpen.lopnColor);
+  }
+#endif
+
+  if (filled)
+    oldpen = SelectObject (hdc, GetStockObject (NULL_PEN));
+  else
+    oldbrush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
+  
+  if (!Rectangle (hdc, x, y, x+width+1, y+height+1))
+    g_warning ("gdk_draw_rectangle: Rectangle failed");
+  
+  if (filled)
+    SelectObject (hdc, oldpen);
+  else
+    SelectObject (hdc, oldbrush);
+
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_arc (GdkDrawable *drawable,
+             GdkGC       *gc,
+             gint         filled,
+             gint         x,
+             gint         y,
+             gint         width,
+             gint         height,
+             gint         angle1,
+             gint         angle2)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  if (width == -1)
+    width = drawable_private->width;
+  if (height == -1)
+    height = drawable_private->height;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+
+  nXStartArc = x + width/2 + (int) (sin(angle1/64.*M_TWOPI)*width);
+  nYStartArc = y + height/2 + (int) (cos(angle1/64.*M_TWOPI)*height);
+  nXEndArc = x + width/2 + (int) (sin(angle2/64.*M_TWOPI)*width);
+  nYEndArc = y + height/2 + (int) (cos(angle2/64.*M_TWOPI)*height);
+
+  if (filled)
+    {
+      if (!Pie (hdc, x, y, x+width, y+height,
+               nXStartArc, nYStartArc, nXEndArc, nYEndArc))
+       g_warning ("gdk_draw_arc: Pie failed");
+    }
+  else
+    {
+      if (!Arc (hdc, x, y, x+width, y+height,
+               nXStartArc, nYStartArc, nXEndArc, nYEndArc))
+       g_warning ("gdk_draw_arc: Arc failed");
+    }
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_polygon (GdkDrawable *drawable,
+                 GdkGC       *gc,
+                 gint         filled,
+                 GdkPoint    *points,
+                 gint         npoints)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  POINT *pts;
+  int i;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+  pts = g_malloc ((npoints+1) * sizeof (POINT));
+
+  GDK_NOTE (MISC, g_print ("gdk_draw_polygon: %#x (%d) %d\n",
+                          drawable_private->xwindow, gc_private,
+                          npoints));
+
+  for (i = 0; i < npoints; i++)
+    {
+      pts[i].x = points[i].x;
+      pts[i].y = points[i].y;
+    }
+  
+  if ((points[0].x != points[npoints-1].x) ||
+      (points[0].y != points[npoints-1].y)) 
+    {
+      pts[npoints].x = points[0].x;
+      pts[npoints].y = points[0].y;
+      npoints++;
+    }
+  if (filled)
+    {
+      if (!Polygon (hdc, pts, npoints))
+       g_warning ("gdk_draw_polygon: Polygon failed");
+    }
+  else
+    {
+      if (!Polyline (hdc, pts, npoints))
+       g_warning ("gdk_draw_polygon: Polyline failed");
+    }
+  g_free (pts);
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+/* gdk_draw_string
+ */
+void
+gdk_draw_string (GdkDrawable *drawable,
+                GdkFont     *font,
+                GdkGC       *gc,
+                gint         x,
+                gint         y,
+                const gchar *string)
+{
+  gdk_draw_text (drawable, font, gc, x, y, string, strlen (string));
+}
+
+/* gdk_draw_text
+ *
+ * Modified by Li-Da Lho to draw 16 bits and Multibyte strings
+ *
+ * Interface changed: add "GdkFont *font" to specify font or fontset explicitely
+ */
+void
+gdk_draw_text (GdkDrawable *drawable,
+              GdkFont     *font,
+              GdkGC       *gc,
+              gint         x,
+              gint         y,
+              const gchar *text,
+              gint         text_length)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkFontPrivate *font_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  HFONT xfont;
+  HGDIOBJ oldfont;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (text != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+  font_private = (GdkFontPrivate*) font;
+
+  if (font->type == GDK_FONT_FONT)
+    {
+      hdc = gdk_gc_predraw (drawable_private, gc_private);
+      xfont = (HFONT) font_private->xfont;
+
+      GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d) %#x "
+                              "+%d+%d font: %#x \"%.*s\" length: %d\n",
+                              drawable_private->xwindow,
+                              gc_private, gc_private->xgc,
+                              x, y, xfont,
+                              (text_length > 10 ? 10 : text_length),
+                              text, text_length));
+      
+      if ((oldfont = SelectObject (hdc, xfont)) == NULL)
+       g_warning ("gdk_draw_text: SelectObject failed");
+      if (!TextOutA (hdc, x, y, text, text_length))
+       g_warning ("gdk_draw_text: TextOutA failed");
+      SelectObject (hdc, oldfont);
+      gdk_gc_postdraw (drawable_private, gc_private);
+    }
+  else
+    g_error ("undefined font type");
+}
+
+void
+gdk_draw_text_wc (GdkDrawable   *drawable,
+                 GdkFont        *font,
+                 GdkGC          *gc,
+                 gint            x,
+                 gint            y,
+                 const GdkWChar *text,
+                 gint            text_length)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkFontPrivate *font_private;
+  GdkGCPrivate *gc_private;
+  gint i;
+  wchar_t *wcstr;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (text != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+  font_private = (GdkFontPrivate*) font;
+
+  if (font->type == GDK_FONT_FONT)
+    {
+      HDC hdc;
+      HFONT xfont;
+      HGDIOBJ oldfont;
+
+      hdc = gdk_gc_predraw (drawable_private, gc_private);
+      xfont = (HFONT) font_private->xfont;
+
+      GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d) %#x "
+                              "+%d+%d font: %#x length: %d\n",
+                              drawable_private->xwindow,
+                              gc_private, gc_private->xgc,
+                              x, y, xfont,
+                              text_length));
+      
+      if ((oldfont = SelectObject (hdc, xfont)) == NULL)
+       g_warning ("gdk_draw_text: SelectObject failed");
+      wcstr = g_new (wchar_t, text_length);
+      for (i = 0; i < text_length; i++)
+       wcstr[i] = text[i];
+      if (!TextOutW (hdc, x, y, wcstr, text_length))
+       g_warning ("gdk_draw_text: TextOutW failed");
+      g_free (wcstr);
+      SelectObject (hdc, oldfont);
+      gdk_gc_postdraw (drawable_private, gc_private);
+    }
+  else
+    g_error ("undefined font type");
+}
+
+void
+gdk_draw_pixmap (GdkDrawable *drawable,
+                GdkGC       *gc,
+                GdkPixmap   *src,
+                gint         xsrc,
+                gint         ysrc,
+                gint         xdest,
+                gint         ydest,
+                gint         width,
+                gint         height)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkWindowPrivate *src_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  HDC srcdc;
+  HGDIOBJ hgdiobj;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (src != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  src_private = (GdkWindowPrivate*) src;
+  if (drawable_private->destroyed || src_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  if (width == -1)
+    width = src_private->width;
+  if (height == -1)
+    height = src_private->height;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+
+  GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x destdc: (%d) %#x "
+                          "src: %#x %dx%d@+%d+%d\n",
+                          drawable_private->xwindow, gc_private, hdc,
+                          src_private->xwindow,
+                          width, height, xdest, ydest));
+
+  /* Strangely enough, this function is called also to bitblt
+   * from a window.
+   */
+  if (src_private->window_type == GDK_WINDOW_PIXMAP)
+    {
+      if ((srcdc = CreateCompatibleDC (hdc)) == NULL)
+       g_warning ("gdk_draw_pixmap: CreateCompatibleDC failed");
+      
+      if ((hgdiobj = SelectObject (srcdc, src_private->xwindow)) == NULL)
+       g_warning ("gdk_draw_pixmap: SelectObject #1 failed");
+      
+      if (!BitBlt (hdc, xdest, ydest, width, height,
+                  srcdc, xsrc, ysrc, SRCCOPY))
+       g_warning ("gdk_draw_pixmap: BitBlt failed");
+      
+      if ((SelectObject (srcdc, hgdiobj) == NULL))
+       g_warning ("gdk_draw_pixmap: SelectObject #2 failed");
+      
+      if (!DeleteDC (srcdc))
+       g_warning ("gdk_draw_pixmap: DeleteDC failed");
+    }
+  else
+    {
+      if ((srcdc = GetDC (src_private->xwindow)) == NULL)
+       g_warning ("gdk_draw_pixmap: GetDC failed");
+      
+      if (!BitBlt (hdc, xdest, ydest, width, height,
+                  srcdc, xsrc, ysrc, SRCCOPY))
+       g_warning ("gdk_draw_pixmap: BitBlt failed");
+      
+      ReleaseDC (src_private->xwindow, srcdc);
+    }
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_image (GdkDrawable *drawable,
+               GdkGC       *gc,
+               GdkImage    *image,
+               gint         xsrc,
+               gint         ysrc,
+               gint         xdest,
+               gint         ydest,
+               gint         width,
+               gint         height)
+{
+  GdkImagePrivate *image_private;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (image != NULL);
+  g_return_if_fail (gc != NULL);
+
+  image_private = (GdkImagePrivate*) image;
+
+  g_return_if_fail (image_private->image_put != NULL);
+
+  if (width == -1)
+    width = image->width;
+  if (height == -1)
+    height = image->height;
+
+  (* image_private->image_put) (drawable, gc, image, xsrc, ysrc,
+                               xdest, ydest, width, height);
+}
+
+void
+gdk_draw_points (GdkDrawable *drawable,
+                GdkGC       *gc,
+                GdkPoint    *points,
+                gint         npoints)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  HBRUSH hbr;
+  int i;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail ((points != NULL) && (npoints > 0));
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+  hbr = GetCurrentObject (hdc, OBJ_BRUSH);
+  
+  for (i = 0; i < npoints; i++)
+    {
+      RECT rect;
+      
+      rect.left = points[i].x;
+      rect.top = points[i].y;
+      rect.right = rect.left + 1;
+      rect.bottom = rect.top + 1;
+      if (!FillRect (hdc, &rect, hbr))
+       g_warning ("gdk_draw_points: FillRect failed");
+    }
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_segments (GdkDrawable *drawable,
+                  GdkGC       *gc,
+                  GdkSegment  *segs,
+                  gint         nsegs)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  int i;
+
+  if (nsegs <= 0)
+    return;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (segs != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+
+  for (i = 0; i < nsegs; i++)
+    {
+      MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL);
+      if (!LineTo (hdc, segs[i].x2, segs[i].y2))
+       g_warning ("gdk_draw_segments: LineTo #1 failed");
+      
+      /* Draw end pixel */
+      if (gc_private->pen_width == 1)
+       if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
+         g_warning ("gdk_draw_segments: LineTo #2 failed");
+    }
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_lines (GdkDrawable *drawable,
+               GdkGC       *gc,
+               GdkPoint    *points,
+               gint         npoints)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  POINT *pts;
+  int i;
+
+  if (npoints <= 0)
+    return;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (points != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  gc_private = (GdkGCPrivate*) gc;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+#if 1
+  pts = g_malloc (npoints * sizeof (POINT));
+
+  for (i = 0; i < npoints; i++)
+    {
+      pts[i].x = points[i].x;
+      pts[i].y = points[i].y;
+    }
+  
+  if (!Polyline (hdc, pts, npoints))
+    g_warning ("gdk_draw_lines: Polyline failed");
+  
+  g_free (pts);
+  
+  /* Draw end pixel */
+  if (gc_private->pen_width == 1)
+    {
+      MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL);
+      if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
+       g_warning ("gdk_draw_lines: LineTo failed");
+    }
+#else
+  MoveToEx (hdc, points[0].x, points[0].y, NULL);
+  for (i = 1; i < npoints; i++)
+    if (!LineTo (hdc, points[i].x, points[i].y))
+      g_warning ("gdk_draw_lines: LineTo #1 failed");
+  
+  /* Draw end pixel */
+  if (gc_private->pen_width == 1)
+    if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
+      g_warning ("gdk_draw_lines: LineTo #2 failed");
+#endif 
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
diff --git a/gdk/win32/gdkdrawable-win32.c b/gdk/win32/gdkdrawable-win32.c
new file mode 100644 (file)
index 0000000..700bdb5
--- /dev/null
@@ -0,0 +1,655 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include "gdk.h"
+#include "gdkprivate.h"
+
+#ifndef M_TWOPI
+#define M_TWOPI         (2.0 * 3.14159265358979323846)
+#endif
+
+void
+gdk_draw_point (GdkDrawable *drawable,
+                GdkGC       *gc,
+                gint         x,
+                gint         y)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  HBRUSH hbr;
+  RECT rect;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+  hbr = GetCurrentObject (hdc, OBJ_BRUSH);
+  /* We use FillRect because SetPixel wants the COLORREF directly,
+   * and doesn't use the current brush, which is what we want.
+   */
+  rect.left = x;
+  rect.top = y;
+  rect.right = rect.left + 1;
+  rect.bottom = rect.top + 1;
+  FillRect (hdc, &rect, hbr);
+  
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_line (GdkDrawable *drawable,
+              GdkGC       *gc,
+              gint         x1,
+              gint         y1,
+              gint         x2,
+              gint         y2)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+    
+  GDK_NOTE (MISC, g_print ("gdk_draw_line: %#x (%d) +%d+%d..+%d+%d\n",
+                          drawable_private->xwindow, gc_private,
+                          x1, y1, x2, y2));
+  
+  MoveToEx (hdc, x1, y1, NULL);
+  if (!LineTo (hdc, x2, y2))
+    g_warning ("gdk_draw_line: LineTo #1 failed");
+  /* LineTo doesn't draw the last point, so if we have a pen width of 1,
+   * we draw the end pixel separately... With wider pens it hopefully
+   * doesn't matter?
+   */
+  if (gc_private->pen_width == 1)
+    if (!LineTo (hdc, x2 + 1, y2))
+      g_warning ("gdk_draw_line: LineTo #2 failed");
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_rectangle (GdkDrawable *drawable,
+                   GdkGC       *gc,
+                   gint         filled,
+                   gint         x,
+                   gint         y,
+                   gint         width,
+                   gint         height)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  LOGBRUSH lb;
+  HPEN hpen;
+  HBRUSH hbr;
+  HGDIOBJ oldpen, oldbrush;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  if (width == -1)
+    width = drawable_private->width;
+  if (height == -1)
+    height = drawable_private->height;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+
+  GDK_NOTE (MISC, g_print ("gdk_draw_rectangle: %#x (%d) %s%dx%d@+%d+%d\n",
+                          drawable_private->xwindow,
+                          gc_private,
+                          (filled ? "fill " : ""),
+                          width, height, x, y));
+    
+#if 0
+  {
+    HBRUSH hbr = GetCurrentObject (hdc, OBJ_BRUSH);
+    HPEN hpen = GetCurrentObject (hdc, OBJ_PEN);
+    LOGBRUSH lbr;
+    LOGPEN lpen;
+    GetObject (hbr, sizeof (lbr), &lbr);
+    GetObject (hpen, sizeof (lpen), &lpen);
+    
+    g_print ("current brush: style = %s, color = 0x%.08x\n",
+            (lbr.lbStyle == BS_SOLID ? "SOLID" : "???"),
+            lbr.lbColor);
+    g_print ("current pen: style = %s, width = %d, color = 0x%.08x\n",
+            (lpen.lopnStyle == PS_SOLID ? "SOLID" : "???"),
+            lpen.lopnWidth,
+            lpen.lopnColor);
+  }
+#endif
+
+  if (filled)
+    oldpen = SelectObject (hdc, GetStockObject (NULL_PEN));
+  else
+    oldbrush = SelectObject (hdc, GetStockObject (HOLLOW_BRUSH));
+  
+  if (!Rectangle (hdc, x, y, x+width+1, y+height+1))
+    g_warning ("gdk_draw_rectangle: Rectangle failed");
+  
+  if (filled)
+    SelectObject (hdc, oldpen);
+  else
+    SelectObject (hdc, oldbrush);
+
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_arc (GdkDrawable *drawable,
+             GdkGC       *gc,
+             gint         filled,
+             gint         x,
+             gint         y,
+             gint         width,
+             gint         height,
+             gint         angle1,
+             gint         angle2)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  int nXStartArc, nYStartArc, nXEndArc, nYEndArc;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  if (width == -1)
+    width = drawable_private->width;
+  if (height == -1)
+    height = drawable_private->height;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+
+  nXStartArc = x + width/2 + (int) (sin(angle1/64.*M_TWOPI)*width);
+  nYStartArc = y + height/2 + (int) (cos(angle1/64.*M_TWOPI)*height);
+  nXEndArc = x + width/2 + (int) (sin(angle2/64.*M_TWOPI)*width);
+  nYEndArc = y + height/2 + (int) (cos(angle2/64.*M_TWOPI)*height);
+
+  if (filled)
+    {
+      if (!Pie (hdc, x, y, x+width, y+height,
+               nXStartArc, nYStartArc, nXEndArc, nYEndArc))
+       g_warning ("gdk_draw_arc: Pie failed");
+    }
+  else
+    {
+      if (!Arc (hdc, x, y, x+width, y+height,
+               nXStartArc, nYStartArc, nXEndArc, nYEndArc))
+       g_warning ("gdk_draw_arc: Arc failed");
+    }
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_polygon (GdkDrawable *drawable,
+                 GdkGC       *gc,
+                 gint         filled,
+                 GdkPoint    *points,
+                 gint         npoints)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  POINT *pts;
+  int i;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+  pts = g_malloc ((npoints+1) * sizeof (POINT));
+
+  GDK_NOTE (MISC, g_print ("gdk_draw_polygon: %#x (%d) %d\n",
+                          drawable_private->xwindow, gc_private,
+                          npoints));
+
+  for (i = 0; i < npoints; i++)
+    {
+      pts[i].x = points[i].x;
+      pts[i].y = points[i].y;
+    }
+  
+  if ((points[0].x != points[npoints-1].x) ||
+      (points[0].y != points[npoints-1].y)) 
+    {
+      pts[npoints].x = points[0].x;
+      pts[npoints].y = points[0].y;
+      npoints++;
+    }
+  if (filled)
+    {
+      if (!Polygon (hdc, pts, npoints))
+       g_warning ("gdk_draw_polygon: Polygon failed");
+    }
+  else
+    {
+      if (!Polyline (hdc, pts, npoints))
+       g_warning ("gdk_draw_polygon: Polyline failed");
+    }
+  g_free (pts);
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+/* gdk_draw_string
+ */
+void
+gdk_draw_string (GdkDrawable *drawable,
+                GdkFont     *font,
+                GdkGC       *gc,
+                gint         x,
+                gint         y,
+                const gchar *string)
+{
+  gdk_draw_text (drawable, font, gc, x, y, string, strlen (string));
+}
+
+/* gdk_draw_text
+ *
+ * Modified by Li-Da Lho to draw 16 bits and Multibyte strings
+ *
+ * Interface changed: add "GdkFont *font" to specify font or fontset explicitely
+ */
+void
+gdk_draw_text (GdkDrawable *drawable,
+              GdkFont     *font,
+              GdkGC       *gc,
+              gint         x,
+              gint         y,
+              const gchar *text,
+              gint         text_length)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkFontPrivate *font_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  HFONT xfont;
+  HGDIOBJ oldfont;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (text != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+  font_private = (GdkFontPrivate*) font;
+
+  if (font->type == GDK_FONT_FONT)
+    {
+      hdc = gdk_gc_predraw (drawable_private, gc_private);
+      xfont = (HFONT) font_private->xfont;
+
+      GDK_NOTE (MISC, g_print ("gdk_draw_text: %#x (%d) %#x "
+                              "+%d+%d font: %#x \"%.*s\" length: %d\n",
+                              drawable_private->xwindow,
+                              gc_private, gc_private->xgc,
+                              x, y, xfont,
+                              (text_length > 10 ? 10 : text_length),
+                              text, text_length));
+      
+      if ((oldfont = SelectObject (hdc, xfont)) == NULL)
+       g_warning ("gdk_draw_text: SelectObject failed");
+      if (!TextOutA (hdc, x, y, text, text_length))
+       g_warning ("gdk_draw_text: TextOutA failed");
+      SelectObject (hdc, oldfont);
+      gdk_gc_postdraw (drawable_private, gc_private);
+    }
+  else
+    g_error ("undefined font type");
+}
+
+void
+gdk_draw_text_wc (GdkDrawable   *drawable,
+                 GdkFont        *font,
+                 GdkGC          *gc,
+                 gint            x,
+                 gint            y,
+                 const GdkWChar *text,
+                 gint            text_length)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkFontPrivate *font_private;
+  GdkGCPrivate *gc_private;
+  gint i;
+  wchar_t *wcstr;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (text != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+  font_private = (GdkFontPrivate*) font;
+
+  if (font->type == GDK_FONT_FONT)
+    {
+      HDC hdc;
+      HFONT xfont;
+      HGDIOBJ oldfont;
+
+      hdc = gdk_gc_predraw (drawable_private, gc_private);
+      xfont = (HFONT) font_private->xfont;
+
+      GDK_NOTE (MISC, g_print ("gdk_draw_text_wc: %#x (%d) %#x "
+                              "+%d+%d font: %#x length: %d\n",
+                              drawable_private->xwindow,
+                              gc_private, gc_private->xgc,
+                              x, y, xfont,
+                              text_length));
+      
+      if ((oldfont = SelectObject (hdc, xfont)) == NULL)
+       g_warning ("gdk_draw_text: SelectObject failed");
+      wcstr = g_new (wchar_t, text_length);
+      for (i = 0; i < text_length; i++)
+       wcstr[i] = text[i];
+      if (!TextOutW (hdc, x, y, wcstr, text_length))
+       g_warning ("gdk_draw_text: TextOutW failed");
+      g_free (wcstr);
+      SelectObject (hdc, oldfont);
+      gdk_gc_postdraw (drawable_private, gc_private);
+    }
+  else
+    g_error ("undefined font type");
+}
+
+void
+gdk_draw_pixmap (GdkDrawable *drawable,
+                GdkGC       *gc,
+                GdkPixmap   *src,
+                gint         xsrc,
+                gint         ysrc,
+                gint         xdest,
+                gint         ydest,
+                gint         width,
+                gint         height)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkWindowPrivate *src_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  HDC srcdc;
+  HGDIOBJ hgdiobj;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (src != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  src_private = (GdkWindowPrivate*) src;
+  if (drawable_private->destroyed || src_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  if (width == -1)
+    width = src_private->width;
+  if (height == -1)
+    height = src_private->height;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+
+  GDK_NOTE (MISC, g_print ("gdk_draw_pixmap: dest: %#x destdc: (%d) %#x "
+                          "src: %#x %dx%d@+%d+%d\n",
+                          drawable_private->xwindow, gc_private, hdc,
+                          src_private->xwindow,
+                          width, height, xdest, ydest));
+
+  /* Strangely enough, this function is called also to bitblt
+   * from a window.
+   */
+  if (src_private->window_type == GDK_WINDOW_PIXMAP)
+    {
+      if ((srcdc = CreateCompatibleDC (hdc)) == NULL)
+       g_warning ("gdk_draw_pixmap: CreateCompatibleDC failed");
+      
+      if ((hgdiobj = SelectObject (srcdc, src_private->xwindow)) == NULL)
+       g_warning ("gdk_draw_pixmap: SelectObject #1 failed");
+      
+      if (!BitBlt (hdc, xdest, ydest, width, height,
+                  srcdc, xsrc, ysrc, SRCCOPY))
+       g_warning ("gdk_draw_pixmap: BitBlt failed");
+      
+      if ((SelectObject (srcdc, hgdiobj) == NULL))
+       g_warning ("gdk_draw_pixmap: SelectObject #2 failed");
+      
+      if (!DeleteDC (srcdc))
+       g_warning ("gdk_draw_pixmap: DeleteDC failed");
+    }
+  else
+    {
+      if ((srcdc = GetDC (src_private->xwindow)) == NULL)
+       g_warning ("gdk_draw_pixmap: GetDC failed");
+      
+      if (!BitBlt (hdc, xdest, ydest, width, height,
+                  srcdc, xsrc, ysrc, SRCCOPY))
+       g_warning ("gdk_draw_pixmap: BitBlt failed");
+      
+      ReleaseDC (src_private->xwindow, srcdc);
+    }
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_image (GdkDrawable *drawable,
+               GdkGC       *gc,
+               GdkImage    *image,
+               gint         xsrc,
+               gint         ysrc,
+               gint         xdest,
+               gint         ydest,
+               gint         width,
+               gint         height)
+{
+  GdkImagePrivate *image_private;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (image != NULL);
+  g_return_if_fail (gc != NULL);
+
+  image_private = (GdkImagePrivate*) image;
+
+  g_return_if_fail (image_private->image_put != NULL);
+
+  if (width == -1)
+    width = image->width;
+  if (height == -1)
+    height = image->height;
+
+  (* image_private->image_put) (drawable, gc, image, xsrc, ysrc,
+                               xdest, ydest, width, height);
+}
+
+void
+gdk_draw_points (GdkDrawable *drawable,
+                GdkGC       *gc,
+                GdkPoint    *points,
+                gint         npoints)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  HBRUSH hbr;
+  int i;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail ((points != NULL) && (npoints > 0));
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+  hbr = GetCurrentObject (hdc, OBJ_BRUSH);
+  
+  for (i = 0; i < npoints; i++)
+    {
+      RECT rect;
+      
+      rect.left = points[i].x;
+      rect.top = points[i].y;
+      rect.right = rect.left + 1;
+      rect.bottom = rect.top + 1;
+      if (!FillRect (hdc, &rect, hbr))
+       g_warning ("gdk_draw_points: FillRect failed");
+    }
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_segments (GdkDrawable *drawable,
+                  GdkGC       *gc,
+                  GdkSegment  *segs,
+                  gint         nsegs)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  int i;
+
+  if (nsegs <= 0)
+    return;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (segs != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  gc_private = (GdkGCPrivate*) gc;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+
+  for (i = 0; i < nsegs; i++)
+    {
+      MoveToEx (hdc, segs[i].x1, segs[i].y1, NULL);
+      if (!LineTo (hdc, segs[i].x2, segs[i].y2))
+       g_warning ("gdk_draw_segments: LineTo #1 failed");
+      
+      /* Draw end pixel */
+      if (gc_private->pen_width == 1)
+       if (!LineTo (hdc, segs[i].x2 + 1, segs[i].y2))
+         g_warning ("gdk_draw_segments: LineTo #2 failed");
+    }
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
+
+void
+gdk_draw_lines (GdkDrawable *drawable,
+               GdkGC       *gc,
+               GdkPoint    *points,
+               gint         npoints)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  POINT *pts;
+  int i;
+
+  if (npoints <= 0)
+    return;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (points != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  gc_private = (GdkGCPrivate*) gc;
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+#if 1
+  pts = g_malloc (npoints * sizeof (POINT));
+
+  for (i = 0; i < npoints; i++)
+    {
+      pts[i].x = points[i].x;
+      pts[i].y = points[i].y;
+    }
+  
+  if (!Polyline (hdc, pts, npoints))
+    g_warning ("gdk_draw_lines: Polyline failed");
+  
+  g_free (pts);
+  
+  /* Draw end pixel */
+  if (gc_private->pen_width == 1)
+    {
+      MoveToEx (hdc, points[npoints-1].x, points[npoints-1].y, NULL);
+      if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
+       g_warning ("gdk_draw_lines: LineTo failed");
+    }
+#else
+  MoveToEx (hdc, points[0].x, points[0].y, NULL);
+  for (i = 1; i < npoints; i++)
+    if (!LineTo (hdc, points[i].x, points[i].y))
+      g_warning ("gdk_draw_lines: LineTo #1 failed");
+  
+  /* Draw end pixel */
+  if (gc_private->pen_width == 1)
+    if (!LineTo (hdc, points[npoints-1].x + 1, points[npoints-1].y))
+      g_warning ("gdk_draw_lines: LineTo #2 failed");
+#endif 
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
new file mode 100644 (file)
index 0000000..02c9474
--- /dev/null
@@ -0,0 +1,2963 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-1999 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include "gdk.h"
+#include "gdkx.h"
+#include "gdkprivate.h"
+#include "gdkinput.h"
+#include "gdkkeysyms.h"
+
+#define PING() printf("%s: %d\n",__FILE__,__LINE__),fflush(stdout)
+
+typedef struct _GdkIOClosure GdkIOClosure;
+typedef struct _GdkEventPrivate GdkEventPrivate;
+
+#define DOUBLE_CLICK_TIME      250
+#define TRIPLE_CLICK_TIME      500
+#define DOUBLE_CLICK_DIST      5
+#define TRIPLE_CLICK_DIST      5
+
+typedef enum
+{
+  /* Following flag is set for events on the event queue during
+   * translation and cleared afterwards.
+   */
+  GDK_EVENT_PENDING = 1 << 0
+} GdkEventFlags;
+
+struct _GdkIOClosure
+{
+  GdkInputFunction function;
+  GdkInputCondition condition;
+  GdkDestroyNotify notify;
+  gpointer data;
+};
+
+struct _GdkEventPrivate
+{
+  GdkEvent event;
+  guint    flags;
+};
+
+/* 
+ * Private function declarations
+ */
+
+static GdkEvent *gdk_event_new         (void);
+static gint     gdk_event_apply_filters(MSG      *xevent,
+                                        GdkEvent *event,
+                                        GList    *filters);
+static gint     gdk_event_translate    (GdkEvent *event, 
+                                        MSG      *xevent,
+                                        gboolean *ret_val_flagp,
+                                        gint     *ret_valp);
+static void      gdk_events_queue       (void);
+static GdkEvent *gdk_event_unqueue      (void);
+static gboolean  gdk_event_prepare      (gpointer  source_data, 
+                                        GTimeVal *current_time,
+                                        gint     *timeout);
+static gboolean  gdk_event_check        (gpointer  source_data,
+                                        GTimeVal *current_time);
+static gboolean  gdk_event_dispatch     (gpointer  source_data,
+                                        GTimeVal *current_time,
+                                        gpointer  user_data);
+
+static void     gdk_synthesize_click   (GdkEvent     *event, 
+                                        gint          nclicks);
+
+/* Private variable declarations
+ */
+
+static guint32 button_click_time[2];       /* The last 2 button click times. Used
+                                            *  to determine if the latest button click
+                                            *  is part of a double or triple click.
+                                            */
+static GdkWindow *button_window[2];        /* The last 2 windows to receive button presses.
+                                            *  Also used to determine if the latest button
+                                            *  click is part of a double or triple click.
+                                            */
+static guint button_number[2];             /* The last 2 buttons to be pressed.
+                                            */
+static GdkWindowPrivate *p_grab_window = NULL; /* Window that currently
+                                               * holds the pointer grab
+                                               */
+
+static GdkWindowPrivate *k_grab_window = NULL; /* Window the holds the
+                                               * keyboard grab
+                                               */
+
+static GList *client_filters;  /* Filters for client messages */
+
+static gboolean p_grab_automatic;
+static GdkEventMask p_grab_event_mask;
+static gboolean p_grab_owner_events, k_grab_owner_events;
+static HCURSOR p_grab_cursor;
+
+static GdkEventFunc   event_func = NULL;    /* Callback for events */
+static gpointer       event_data = NULL;
+static GDestroyNotify event_notify = NULL;
+
+static GList *client_filters;              /* Filters for client messages */
+
+/* FIFO's for event queue, and for events put back using
+ * gdk_event_put().
+ */
+static GList *queued_events = NULL;
+static GList *queued_tail = NULL;
+
+static GSourceFuncs event_funcs = {
+  gdk_event_prepare,
+  gdk_event_check,
+  gdk_event_dispatch,
+  (GDestroyNotify)g_free
+};
+
+GPollFD event_poll_fd;
+
+static GdkWindow *curWnd = NULL;
+static HWND active = NULL;
+static gint curX, curY;
+static gdouble curXroot, curYroot;
+static UINT gdk_ping_msg;
+static gboolean ignore_WM_CHAR = FALSE;
+static gboolean is_AltGr_key = FALSE;
+
+LRESULT CALLBACK 
+gdk_WindowProc(HWND hwnd,
+              UINT message,
+              WPARAM wParam,
+              LPARAM lParam)
+{
+  GdkEvent event;
+  GdkEvent *eventp;
+  MSG msg;
+  DWORD pos;
+  gint ret_val;
+  gboolean ret_val_flag;
+
+  GDK_NOTE (EVENTS, g_print ("gdk_WindowProc: %#x\n", message));
+
+  msg.hwnd = hwnd;
+  msg.message = message;
+  msg.wParam = wParam;
+  msg.lParam = lParam;
+  msg.time = GetTickCount ();
+  pos = GetMessagePos ();
+  msg.pt.x = LOWORD (pos);
+  msg.pt.y = HIWORD (pos);
+
+  if (gdk_event_translate (&event, &msg, &ret_val_flag, &ret_val))
+    {
+#if 1
+      /* Compress configure events */
+      if (event.any.type == GDK_CONFIGURE)
+       {
+         GList *list = queued_events;
+
+         while (list != NULL
+                && (((GdkEvent *)list->data)->any.type != GDK_CONFIGURE
+                    || ((GdkEvent *)list->data)->any.window != event.any.window))
+           list = list->next;
+         if (list != NULL)
+           {
+             *((GdkEvent *)list->data) = event;
+             gdk_window_unref (event.any.window);
+             /* Wake up WaitMessage */
+             PostMessage (NULL, gdk_ping_msg, 0, 0);
+             return FALSE;
+           }
+       }
+#endif
+      eventp = gdk_event_new ();
+      *eventp = event;
+
+      gdk_event_queue_append (eventp);
+#if 1
+      /* Wake up WaitMessage */
+      PostMessage (NULL, gdk_ping_msg, 0, 0);
+#endif
+      if (ret_val_flag)
+       return ret_val;
+      else
+       return FALSE;
+    }
+
+  if (ret_val_flag)
+    return ret_val;
+  else
+    return DefWindowProc (hwnd, message, wParam, lParam);
+}
+
+/*********************************************
+ * Functions for maintaining the event queue *
+ *********************************************/
+
+/*************************************************************
+ * gdk_event_queue_find_first:
+ *     Find the first event on the queue that is not still
+ *     being filled in.
+ *   arguments:
+ *     
+ *   results:
+ *     Pointer to the list node for that event, or NULL
+ *************************************************************/
+
+static GList*
+gdk_event_queue_find_first (void)
+{
+  GList *tmp_list = queued_events;
+
+  while (tmp_list)
+    {
+      GdkEventPrivate *event = tmp_list->data;
+      if (!(event->flags & GDK_EVENT_PENDING))
+       return tmp_list;
+
+      tmp_list = g_list_next (tmp_list);
+    }
+
+  return NULL;
+}
+
+/*************************************************************
+ * gdk_event_queue_remove_link:
+ *     Remove a specified list node from the event queue.
+ *   arguments:
+ *     node: Node to remove.
+ *   results:
+ *************************************************************/
+
+static void
+gdk_event_queue_remove_link (GList *node)
+{
+  if (node->prev)
+    node->prev->next = node->next;
+  else
+    queued_events = node->next;
+  
+  if (node->next)
+    node->next->prev = node->prev;
+  else
+    queued_tail = node->prev;
+  
+}
+
+/*************************************************************
+ * gdk_event_queue_append:
+ *     Append an event onto the tail of the event queue.
+ *   arguments:
+ *     event: Event to append.
+ *   results:
+ *************************************************************/
+
+void
+gdk_event_queue_append (GdkEvent *event)
+{
+  queued_tail = g_list_append (queued_tail, event);
+  
+  if (!queued_events)
+    queued_events = queued_tail;
+  else
+    queued_tail = queued_tail->next;
+}
+
+void 
+gdk_events_init (void)
+{
+  if (g_pipe_readable_msg == 0)
+    g_pipe_readable_msg = RegisterWindowMessage ("g-pipe-readable");
+
+  g_source_add (GDK_PRIORITY_EVENTS, TRUE, &event_funcs, NULL, NULL, NULL);
+
+  event_poll_fd.fd = G_WIN32_MSG_HANDLE;
+  event_poll_fd.events = G_IO_IN;
+  
+  g_main_add_poll (&event_poll_fd, GDK_PRIORITY_EVENTS);
+
+  button_click_time[0] = 0;
+  button_click_time[1] = 0;
+  button_window[0] = NULL;
+  button_window[1] = NULL;
+  button_number[0] = -1;
+  button_number[1] = -1;
+
+  gdk_ping_msg = RegisterWindowMessage ("gdk-ping");
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_events_pending
+ *
+ *   Returns if events are pending on the queue.
+ *
+ * Arguments:
+ *
+ * Results:
+ *   Returns TRUE if events are pending
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gboolean
+gdk_events_pending (void)
+{
+  MSG msg;
+
+  return (gdk_event_queue_find_first() || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE));
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_get_graphics_expose
+ *
+ *   Waits for a GraphicsExpose or NoExpose event
+ *
+ * Arguments:
+ *
+ * Results: 
+ *   For GraphicsExpose events, returns a pointer to the event
+ *   converted into a GdkEvent Otherwise, returns NULL.
+ *
+ * Side effects:
+ *
+ *-------------------------------------------------------------- */
+
+GdkEvent*
+gdk_event_get_graphics_expose (GdkWindow *window)
+{
+  MSG xevent;
+  GdkEvent *event;
+  GdkWindowPrivate *private = (GdkWindowPrivate *) window;
+
+  g_return_val_if_fail (window != NULL, NULL);
+  
+  GDK_NOTE (EVENTS, g_print ("gdk_event_get_graphics_expose\n"));
+
+#if 1
+  /* Some nasty bugs here, just return NULL for now. */
+  return NULL;
+#else
+  if (GetMessage (&xevent, private->xwindow, WM_PAINT, WM_PAINT))
+    {
+      event = gdk_event_new ();
+      
+      if (gdk_event_translate (event, &xevent, NULL, NULL))
+       return event;
+      else
+       gdk_event_free (event);
+    }
+  
+  return NULL; 
+#endif
+}
+
+/************************
+ * Exposure compression *
+ ************************/
+
+/* I don't bother with exposure compression on Win32. Windows compresses
+ * WM_PAINT events by itself.
+ */
+
+/*************************************************************
+ * gdk_event_handler_set:
+ *     
+ *   arguments:
+ *     func: Callback function to be called for each event.
+ *     data: Data supplied to the function
+ *     notify: function called when function is no longer needed
+ * 
+ *   results:
+ *************************************************************/
+
+void 
+gdk_event_handler_set (GdkEventFunc   func,
+                      gpointer       data,
+                      GDestroyNotify notify)
+{
+  if (event_notify)
+    (*event_notify) (event_data);
+
+  event_func = func;
+  event_data = data;
+  event_notify = notify;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_get
+ *
+ *   Gets the next event.
+ *
+ * Arguments:
+ *
+ * Results:
+ *   If an event is waiting that we care about, returns 
+ *   a pointer to that event, to be freed with gdk_event_free.
+ *   Otherwise, returns NULL.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+GdkEvent*
+gdk_event_get (void)
+{
+  gdk_events_queue();
+
+  return gdk_event_unqueue();
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_peek
+ *
+ *   Gets the next event.
+ *
+ * Arguments:
+ *
+ * Results:
+ *   If an event is waiting that we care about, returns 
+ *   a copy of that event, but does not remove it from
+ *   the queue. The pointer is to be freed with gdk_event_free.
+ *   Otherwise, returns NULL.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+GdkEvent*
+gdk_event_peek (void)
+{
+  GList *tmp_list;
+
+  tmp_list = gdk_event_queue_find_first ();
+  
+  if (tmp_list)
+    return gdk_event_copy (tmp_list->data);
+  else
+    return NULL;
+}
+
+void
+gdk_event_put (GdkEvent *event)
+{
+  GdkEvent *new_event;
+  GList *tmp_list;
+  
+  g_return_if_fail (event != NULL);
+  
+  new_event = gdk_event_copy (event);
+
+  gdk_event_queue_append (new_event);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_copy
+ *
+ *   Copy a event structure into new storage.
+ *
+ * Arguments:
+ *   "event" is the event struct to copy.
+ *
+ * Results:
+ *   A new event structure.  Free it with gdk_event_free.
+ *
+ * Side effects:
+ *   The reference count of the window in the event is increased.
+ *
+ *--------------------------------------------------------------
+ */
+
+static GMemChunk *event_chunk = NULL;
+
+static GdkEvent*
+gdk_event_new (void)
+{
+  GdkEventPrivate *new_event;
+  
+  if (event_chunk == NULL)
+    event_chunk = g_mem_chunk_new ("events",
+                                  sizeof (GdkEventPrivate),
+                                  4096,
+                                  G_ALLOC_AND_FREE);
+  
+  new_event = g_chunk_new (GdkEventPrivate, event_chunk);
+  new_event->flags = 0;
+  
+  return (GdkEvent *) new_event;
+}
+
+GdkEvent*
+gdk_event_copy (GdkEvent *event)
+{
+  GdkEvent *new_event;
+  
+  g_return_val_if_fail (event != NULL, NULL);
+  
+  new_event = gdk_event_new ();
+  
+  *new_event = *event;
+  gdk_window_ref (new_event->any.window);
+  
+  switch (event->any.type)
+    {
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+      new_event->key.string = g_strdup (event->key.string);
+      break;
+      
+    case GDK_ENTER_NOTIFY:
+    case GDK_LEAVE_NOTIFY:
+      if (event->crossing.subwindow != NULL)
+       gdk_window_ref (event->crossing.subwindow);
+      break;
+      
+    case GDK_DRAG_ENTER:
+    case GDK_DRAG_LEAVE:
+    case GDK_DRAG_MOTION:
+    case GDK_DRAG_STATUS:
+    case GDK_DROP_START:
+    case GDK_DROP_FINISHED:
+      gdk_drag_context_ref (event->dnd.context);
+      break;
+      
+    default:
+      break;
+    }
+  
+  return new_event;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_free
+ *
+ *   Free a event structure obtained from gdk_event_copy.  Do not use
+ *   with other event structures.
+ *
+ * Arguments:
+ *   "event" is the event struct to free.
+ *
+ * Results:
+ *
+ * Side effects:
+ *   The reference count of the window in the event is decreased and
+ *   might be freed, too.
+ *
+ *-------------------------------------------------------------- */
+
+void
+gdk_event_free (GdkEvent *event)
+{
+  g_return_if_fail (event != NULL);
+
+  g_assert (event_chunk != NULL); /* paranoid */
+  
+  if (event->any.window)
+    gdk_window_unref (event->any.window);
+  
+  switch (event->any.type)
+    {
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+      g_free (event->key.string);
+      break;
+      
+    case GDK_ENTER_NOTIFY:
+    case GDK_LEAVE_NOTIFY:
+      if (event->crossing.subwindow != NULL)
+       gdk_window_unref (event->crossing.subwindow);
+      break;
+      
+    case GDK_DRAG_ENTER:
+    case GDK_DRAG_LEAVE:
+    case GDK_DRAG_MOTION:
+    case GDK_DRAG_STATUS:
+    case GDK_DROP_START:
+    case GDK_DROP_FINISHED:
+      gdk_drag_context_unref (event->dnd.context);
+      break;
+      
+    default:
+      break;
+    }
+  
+  g_mem_chunk_free (event_chunk, event);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_get_time:
+ *    Get the timestamp from an event.
+ *   arguments:
+ *     event:
+ *   results:
+ *    The event's time stamp, if it has one, otherwise
+ *    GDK_CURRENT_TIME.
+ *--------------------------------------------------------------
+ */
+
+guint32
+gdk_event_get_time (GdkEvent *event)
+{
+  if (event)
+    switch (event->type)
+      {
+      case GDK_MOTION_NOTIFY:
+       return event->motion.time;
+      case GDK_BUTTON_PRESS:
+      case GDK_2BUTTON_PRESS:
+      case GDK_3BUTTON_PRESS:
+      case GDK_BUTTON_RELEASE:
+       return event->button.time;
+      case GDK_KEY_PRESS:
+      case GDK_KEY_RELEASE:
+       return event->key.time;
+      case GDK_ENTER_NOTIFY:
+      case GDK_LEAVE_NOTIFY:
+       return event->crossing.time;
+      case GDK_PROPERTY_NOTIFY:
+       return event->property.time;
+      case GDK_SELECTION_CLEAR:
+      case GDK_SELECTION_REQUEST:
+      case GDK_SELECTION_NOTIFY:
+       return event->selection.time;
+      case GDK_PROXIMITY_IN:
+      case GDK_PROXIMITY_OUT:
+       return event->proximity.time;
+      case GDK_DRAG_ENTER:
+      case GDK_DRAG_LEAVE:
+      case GDK_DRAG_MOTION:
+      case GDK_DRAG_STATUS:
+      case GDK_DROP_START:
+      case GDK_DROP_FINISHED:
+       return event->dnd.time;
+      default:                 /* use current time */
+       break;
+      }
+  
+  return GDK_CURRENT_TIME;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_set_show_events
+ *
+ *   Turns on/off the showing of events.
+ *
+ * Arguments:
+ *   "show_events" is a boolean describing whether or
+ *   not to show the events gdk receives.
+ *
+ * Results:
+ *
+ * Side effects:
+ *   When "show_events" is TRUE, calls to "gdk_event_get"
+ *   will output debugging informatin regarding the event
+ *   received to stdout.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_set_show_events (gint show_events)
+{
+  if (show_events)
+    gdk_debug_flags |= GDK_DEBUG_EVENTS;
+  else
+    gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
+}
+
+gint
+gdk_get_show_events (void)
+{
+  return gdk_debug_flags & GDK_DEBUG_EVENTS;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_pointer_grab
+ *
+ *   Grabs the pointer to a specific window
+ *
+ * Arguments:
+ *   "window" is the window which will receive the grab
+ *   "owner_events" specifies whether events will be reported as is,
+ *     or relative to "window"
+ *   "event_mask" masks only interesting events
+ *   "confine_to" limits the cursor movement to the specified window
+ *   "cursor" changes the cursor for the duration of the grab
+ *   "time" specifies the time
+ *
+ * Results:
+ *
+ * Side effects:
+ *   requires a corresponding call to gdk_pointer_ungrab
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_pointer_grab (GdkWindow *    window,
+                 gint            owner_events,
+                 GdkEventMask    event_mask,
+                 GdkWindow *     confine_to,
+                 GdkCursor *     cursor,
+                 guint32         time)
+{
+  GdkWindowPrivate *window_private;
+  HWND xwindow;
+  HWND xconfine_to;
+  HCURSOR xcursor;
+  GdkWindowPrivate *confine_to_private;
+  GdkCursorPrivate *cursor_private;
+  gint return_val;
+
+  g_return_val_if_fail (window != NULL, 0);
+  
+  window_private = (GdkWindowPrivate*) window;
+  confine_to_private = (GdkWindowPrivate*) confine_to;
+  cursor_private = (GdkCursorPrivate*) cursor;
+  
+  xwindow = window_private->xwindow;
+  
+  if (!confine_to || confine_to_private->destroyed)
+    xconfine_to = NULL;
+  else
+    xconfine_to = confine_to_private->xwindow;
+  
+  if (!cursor)
+    xcursor = NULL;
+  else
+    xcursor = cursor_private->xcursor;
+  
+  if (gdk_input_vtable.grab_pointer)
+    return_val = gdk_input_vtable.grab_pointer (window,
+                                               owner_events,
+                                               event_mask,
+                                               confine_to,
+                                               time);
+  else
+    return_val = Success;
+  
+  if (return_val == Success)
+    {
+      if (!window_private->destroyed)
+      {
+       GDK_NOTE (EVENTS, g_print ("gdk_pointer_grab: %#x %s %#x\n",
+                                  xwindow,
+                                  (owner_events ? "TRUE" : "FALSE"),
+                                  xcursor));
+       p_grab_event_mask = event_mask;
+       p_grab_owner_events = owner_events != 0;
+       p_grab_automatic = FALSE;
+
+#if 0 /* Menus don't work if we use mouse capture. Pity, because many other
+       * things work better with mouse capture.
+       */
+       SetCapture (xwindow);
+#endif
+       return_val = GrabSuccess;
+      }
+      else
+       return_val = AlreadyGrabbed;
+    }
+  
+  if (return_val == GrabSuccess)
+    {
+      p_grab_window = window_private;
+      p_grab_cursor = xcursor;
+    }
+  
+  return return_val;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_pointer_ungrab
+ *
+ *   Releases any pointer grab
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_pointer_ungrab (guint32 time)
+{
+  if (gdk_input_vtable.ungrab_pointer)
+    gdk_input_vtable.ungrab_pointer (time);
+#if 0
+  if (GetCapture () != NULL)
+    ReleaseCapture ();
+#endif
+  GDK_NOTE (EVENTS, g_print ("gdk_pointer_ungrab\n"));
+
+  p_grab_window = NULL;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_pointer_is_grabbed
+ *
+ *   Tell wether there is an active x pointer grab in effect
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_pointer_is_grabbed (void)
+{
+  return p_grab_window != NULL;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_keyboard_grab
+ *
+ *   Grabs the keyboard to a specific window
+ *
+ * Arguments:
+ *   "window" is the window which will receive the grab
+ *   "owner_events" specifies whether events will be reported as is,
+ *     or relative to "window"
+ *   "time" specifies the time
+ *
+ * Results:
+ *
+ * Side effects:
+ *   requires a corresponding call to gdk_keyboard_ungrab
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_keyboard_grab (GdkWindow *    window,
+                  gint            owner_events,
+                  guint32         time)
+{
+  GdkWindowPrivate *window_private;
+  gint return_val;
+  
+  g_return_val_if_fail (window != NULL, 0);
+  
+  window_private = (GdkWindowPrivate*) window;
+  
+  GDK_NOTE (EVENTS, g_print ("gdk_keyboard_grab %#x\n",
+                            window_private->xwindow));
+
+  if (!window_private->destroyed)
+    {
+      k_grab_owner_events = owner_events != 0;
+      return_val = GrabSuccess;
+    }
+  else
+    return_val = AlreadyGrabbed;
+
+  if (return_val == GrabSuccess)
+    k_grab_window = window_private;
+  
+  return return_val;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_keyboard_ungrab
+ *
+ *   Releases any keyboard grab
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_keyboard_ungrab (guint32 time)
+{
+  GDK_NOTE (EVENTS, g_print ("gdk_keyboard_ungrab\n"));
+
+  k_grab_window = NULL;
+}
+
+static void
+gdk_io_destroy (gpointer data)
+{
+  GdkIOClosure *closure = data;
+
+  if (closure->notify)
+    closure->notify (closure->data);
+
+  g_free (closure);
+}
+
+static gboolean  
+gdk_io_invoke (GIOChannel   *source,
+              GIOCondition  condition,
+              gpointer      data)
+{
+  GdkIOClosure *closure = data;
+  GdkInputCondition gdk_cond = 0;
+
+  if (condition & (G_IO_IN | G_IO_PRI))
+    gdk_cond |= GDK_INPUT_READ;
+  if (condition & G_IO_OUT)
+    gdk_cond |= GDK_INPUT_WRITE;
+  if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+    gdk_cond |= GDK_INPUT_EXCEPTION;
+
+  if (closure->condition & gdk_cond)
+    closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);
+
+  return TRUE;
+}
+
+gint
+gdk_input_add_full (gint             source,
+                   GdkInputCondition condition,
+                   GdkInputFunction  function,
+                   gpointer          data,
+                   GdkDestroyNotify  destroy)
+{
+  guint result;
+  GdkIOClosure *closure = g_new (GdkIOClosure, 1);
+  GIOChannel *channel;
+  GIOCondition cond = 0;
+
+  closure->function = function;
+  closure->condition = condition;
+  closure->notify = destroy;
+  closure->data = data;
+
+  if (condition & GDK_INPUT_READ)
+    cond |= (G_IO_IN | G_IO_PRI);
+  if (condition & GDK_INPUT_WRITE)
+    cond |= G_IO_OUT;
+  if (condition & GDK_INPUT_EXCEPTION)
+    cond |= G_IO_ERR|G_IO_HUP|G_IO_NVAL;
+
+  channel = g_io_channel_unix_new (source);
+  result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond,
+                               gdk_io_invoke,
+                               closure, gdk_io_destroy);
+  g_io_channel_unref (channel);
+
+  return result;
+}
+
+gint
+gdk_input_add (gint             source,
+              GdkInputCondition condition,
+              GdkInputFunction  function,
+              gpointer          data)
+{
+  return gdk_input_add_full (source, condition, function, data, NULL);
+}
+
+void
+gdk_input_remove (gint tag)
+{
+  g_source_remove (tag);
+}
+
+static gint
+gdk_event_apply_filters (MSG      *xevent,
+                        GdkEvent *event,
+                        GList    *filters)
+{
+  GdkEventFilter *filter;
+  GList *tmp_list;
+  GdkFilterReturn result;
+  
+  tmp_list = filters;
+  
+  while (tmp_list)
+    {
+      filter = (GdkEventFilter *) tmp_list->data;
+      
+      result = (*filter->function) (xevent, event, filter->data);
+      if (result !=  GDK_FILTER_CONTINUE)
+       return result;
+      
+      tmp_list = tmp_list->next;
+    }
+  
+  return GDK_FILTER_CONTINUE;
+}
+
+void 
+gdk_add_client_message_filter (GdkAtom       message_type,
+                              GdkFilterFunc func,
+                              gpointer      data)
+{
+  GdkClientFilter *filter = g_new (GdkClientFilter, 1);
+
+  filter->type = message_type;
+  filter->function = func;
+  filter->data = data;
+  
+  client_filters = g_list_prepend (client_filters, filter);
+}
+
+static void
+synthesize_crossing_events (GdkWindow *window,
+                           MSG       *xevent)
+{
+  GdkEvent *event;
+  GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
+  GdkWindowPrivate *curWnd_private = (GdkWindowPrivate *) curWnd;
+  
+  if (curWnd && (curWnd_private->event_mask & GDK_LEAVE_NOTIFY_MASK))
+    {
+      GDK_NOTE (EVENTS, g_print ("synthesizing LEAVE_NOTIFY event\n"));
+
+      event = gdk_event_new ();
+      event->crossing.type = GDK_LEAVE_NOTIFY;
+      event->crossing.window = curWnd;
+      gdk_window_ref (event->crossing.window);
+      event->crossing.subwindow = NULL;
+      event->crossing.time = xevent->time;
+      event->crossing.x = curX;
+      event->crossing.y = curY;
+      event->crossing.x_root = curXroot;
+      event->crossing.y_root = curYroot;
+      event->crossing.mode = GDK_CROSSING_NORMAL;
+      event->crossing.detail = GDK_NOTIFY_UNKNOWN;
+
+      event->crossing.focus = TRUE; /* ??? */
+      event->crossing.state = 0; /* ??? */
+
+      gdk_event_queue_append (event);
+    }
+
+  if (window_private && (window_private->event_mask & GDK_ENTER_NOTIFY_MASK))
+    {
+      GDK_NOTE (EVENTS, g_print ("synthesizing ENTER_NOTIFY event\n"));
+      
+      event = gdk_event_new ();
+      event->crossing.type = GDK_ENTER_NOTIFY;
+      event->crossing.window = window;
+      gdk_window_ref (event->crossing.window);
+      event->crossing.subwindow = NULL;
+      event->crossing.time = xevent->time;
+      event->crossing.x = LOWORD (xevent->lParam);
+      event->crossing.y = HIWORD (xevent->lParam);
+      event->crossing.x_root = (gfloat) xevent->pt.x;
+      event->crossing.y_root = (gfloat) xevent->pt.y;
+      event->crossing.mode = GDK_CROSSING_NORMAL;
+      event->crossing.detail = GDK_NOTIFY_UNKNOWN;
+      
+      event->crossing.focus = TRUE; /* ??? */
+      event->crossing.state = 0; /* ??? */
+      
+      gdk_event_queue_append (event);
+
+      if (window_private->extension_events != 0
+         && gdk_input_vtable.enter_event)
+       gdk_input_vtable.enter_event (&event->crossing, window);
+    }
+  
+  if (curWnd)
+    gdk_window_unref (curWnd);
+  curWnd = window;
+  gdk_window_ref (curWnd);
+}
+
+static gint
+gdk_event_translate (GdkEvent *event,
+                    MSG      *xevent,
+                    gboolean *ret_val_flagp,
+                    gint     *ret_valp)
+{
+  GdkWindow *window;
+  GdkWindowPrivate *window_private;
+
+  GdkColormapPrivate *colormap_private;
+  HWND owner;
+  DWORD dwStyle;
+  PAINTSTRUCT paintstruct;
+  HDC hdc;
+  HBRUSH hbr;
+  RECT rect;
+  POINT pt;
+  GdkWindowPrivate *curWnd_private;
+  GdkEventMask mask;
+  int button;
+  int i, j;
+  gchar buf[256];
+  gint charcount;
+  gint return_val;
+  gboolean flag;
+  
+  return_val = FALSE;
+  
+  if (ret_val_flagp)
+    *ret_val_flagp = FALSE;
+
+  if (xevent->message == gdk_ping_msg)
+    {
+      /* Messages we post ourselves just to wakeup WaitMessage.  */
+      return FALSE;
+    }
+
+  window = gdk_window_lookup (xevent->hwnd);
+  window_private = (GdkWindowPrivate *) window;
+  
+  if (xevent->message == g_pipe_readable_msg)
+    {
+      GDK_NOTE (EVENTS, g_print ("g_pipe_readable_msg: %d %d\n",
+                                xevent->wParam, xevent->lParam));
+
+      g_io_channel_win32_pipe_readable (xevent->wParam, xevent->lParam);
+      return FALSE;
+    }
+
+  if (window != NULL)
+    gdk_window_ref (window);
+  else
+    {
+      /* Handle WM_QUIT here ? */
+      if (xevent->message == WM_QUIT)
+       {
+         GDK_NOTE (EVENTS, g_print ("WM_QUIT: %d\n", xevent->wParam));
+         exit (xevent->wParam);
+       }
+      else if (xevent->message == WM_MOVE
+              || xevent->message == WM_SIZE)
+       {
+         /* It's quite normal to get these messages before we have
+          * had time to register the window in our lookup table, or
+          * when the window is being destroyed and we already have
+          * removed it. Repost the same message to our queue so that
+          * we will get it later when we are prepared.
+          */
+         PostMessage (xevent->hwnd, xevent->message,
+                      xevent->wParam, xevent->lParam);
+       }
+      else if (xevent->message == WM_NCCREATE
+              || xevent->message == WM_CREATE
+              || xevent->message == WM_GETMINMAXINFO
+              || xevent->message == WM_NCCALCSIZE
+              || xevent->message == WM_NCDESTROY
+              || xevent->message == WM_DESTROY)
+       {
+         /* Nothing */
+       }
+      return FALSE;
+    }
+  
+  event->any.window = window;
+
+  if (window_private && window_private->destroyed)
+    {
+    }
+  else
+    {
+      /* Check for filters for this window */
+      GdkFilterReturn result;
+      result = gdk_event_apply_filters (xevent, event,
+                                       window_private
+                                       ?window_private->filters
+                                       :gdk_default_filters);
+      
+      if (result != GDK_FILTER_CONTINUE)
+       {
+         return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
+       }
+    }
+
+  if (xevent->message == gdk_selection_notify_msg)
+    {
+      GDK_NOTE (SELECTION, g_print ("gdk_selection_notify_msg: %#x\n",
+                                   xevent->hwnd));
+
+      event->selection.type = GDK_SELECTION_NOTIFY;
+      event->selection.window = window;
+      event->selection.selection = xevent->wParam;
+      event->selection.target = xevent->lParam;
+      event->selection.property = gdk_selection_property;
+      event->selection.time = xevent->time;
+
+      return_val = window_private && !window_private->destroyed;
+
+      /* Will pass through switch below without match */
+    }
+  else if (xevent->message == gdk_selection_request_msg)
+    {
+      GDK_NOTE (SELECTION, g_print ("gdk_selection_request_msg: %#x\n",
+                                   xevent->hwnd));
+
+      event->selection.type = GDK_SELECTION_REQUEST;
+      event->selection.window = window;
+      event->selection.selection = gdk_clipboard_atom;
+      event->selection.target = GDK_TARGET_STRING;
+      event->selection.property = gdk_selection_property;
+      event->selection.requestor = (guint32) xevent->hwnd;
+      event->selection.time = xevent->time;
+
+      return_val = window_private && !window_private->destroyed;
+
+      /* Again, will pass through switch below without match */
+    }
+  else if (xevent->message == gdk_selection_clear_msg)
+    {
+      GDK_NOTE (SELECTION, g_print ("gdk_selection_clear_msg: %#x\n",
+                                   xevent->hwnd));
+
+      event->selection.type = GDK_SELECTION_CLEAR;
+      event->selection.window = window;
+      event->selection.selection = xevent->wParam;
+      event->selection.time = xevent->time;
+
+      return_val = window_private && !window_private->destroyed;
+
+      /* Once again, we will pass through switch below without match */
+    }
+  else
+    {
+      GList *tmp_list;
+      GdkFilterReturn result = GDK_FILTER_CONTINUE;
+
+      tmp_list = client_filters;
+      while (tmp_list)
+       {
+         GdkClientFilter *filter = tmp_list->data;
+         if (filter->type == xevent->message)
+           {
+             GDK_NOTE (EVENTS, g_print ("client filter matched\n"));
+             result = (*filter->function) (xevent, event, filter->data);
+             switch (result)
+               {
+               case GDK_FILTER_REMOVE:
+                 return_val = FALSE;
+                 break;
+
+               case GDK_FILTER_TRANSLATE:
+                 return_val = TRUE;
+                 break;
+
+               case GDK_FILTER_CONTINUE:
+                 return_val = TRUE;
+                 event->client.type = GDK_CLIENT_EVENT;
+                 event->client.window = window;
+                 event->client.message_type = xevent->message;
+                 event->client.data_format = 0;
+                 event->client.data.l[0] = xevent->wParam;
+                 event->client.data.l[1] = xevent->lParam;
+                 break;
+               }
+             goto bypass_switch; /* Ouch */
+           }
+         tmp_list = tmp_list->next;
+       }
+    }
+
+  switch (xevent->message)
+    {
+    case WM_SYSKEYUP:
+    case WM_SYSKEYDOWN:
+      GDK_NOTE (EVENTS,
+               g_print ("WM_SYSKEY%s: %#x  key: %s  %#x %#.08x\n",
+                        (xevent->message == WM_SYSKEYUP ? "UP" : "DOWN"),
+                        xevent->hwnd,
+                        (GetKeyNameText (xevent->lParam, buf,
+                                         sizeof (buf)) > 0 ?
+                         buf : ""),
+                        xevent->wParam,
+                        xevent->lParam));
+
+      /* Let the system handle Alt-Tab and Alt-Enter */
+      if (xevent->wParam == VK_TAB
+         || xevent->wParam == VK_RETURN
+         || xevent->wParam == VK_F4)
+       break;
+      /* If posted without us having keyboard focus, ignore */
+      if (!(xevent->lParam & 0x20000000))
+       break;
+#if 0
+      /* don't generate events for just the Alt key */
+      if (xevent->wParam == VK_MENU)
+       break;
+#endif
+      /* Jump to code in common with WM_KEYUP and WM_KEYDOWN */
+      goto keyup_or_down;
+
+    case WM_KEYUP:
+    case WM_KEYDOWN:
+      GDK_NOTE (EVENTS, 
+               g_print ("WM_KEY%s: %#x  key: %s  %#x %#.08x\n",
+                        (xevent->message == WM_KEYUP ? "UP" : "DOWN"),
+                        xevent->hwnd,
+                        (GetKeyNameText (xevent->lParam, buf,
+                                         sizeof (buf)) > 0 ?
+                         buf : ""),
+                        xevent->wParam,
+                        xevent->lParam));
+
+      ignore_WM_CHAR = TRUE;
+    keyup_or_down:
+      if (k_grab_window != NULL
+         && !k_grab_owner_events)
+       {
+         /* Keyboard is grabbed with owner_events FALSE */
+         GDK_NOTE (EVENTS,
+                   g_print ("grabbed, owner_events FALSE, "
+                            "sending to %#x\n", k_grab_window->xwindow));
+         event->key.window = (GdkWindow *) k_grab_window;
+       }
+      else if (window_private
+              && (((xevent->message == WM_KEYUP
+                    || xevent->message == WM_SYSKEYUP)
+                   && !(window_private->event_mask & GDK_KEY_RELEASE_MASK))
+                  || ((xevent->message == WM_KEYDOWN
+                       || xevent->message == WM_SYSKEYDOWN)
+                      && !(window_private->event_mask & GDK_KEY_PRESS_MASK))))
+       {
+         /* Owner window doesn't want it */
+         if (k_grab_window != NULL
+             && k_grab_owner_events)
+           {
+             /* Keyboard is grabbed with owner_events TRUE */
+             GDK_NOTE (EVENTS,
+                       g_print ("grabbed, owner_events TRUE, doesn't want it, "
+                                "sending to %#x\n", k_grab_window->xwindow));
+             event->key.window = (GdkWindow *) k_grab_window;
+           }
+         else
+           {
+             /* Owner doesn't want it, neither is it grabbed, so
+              * propagate to parent.
+              */
+             if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+               break;
+             gdk_window_unref (window);
+             window = window_private->parent;
+             gdk_window_ref (window);
+             window_private = (GdkWindowPrivate *) window;
+             GDK_NOTE (EVENTS,
+                       g_print ("not wanted, not grabbed, "
+                                "sending to %#x\n", window_private->xwindow));
+             goto keyup_or_down;
+           }
+       }
+             
+      switch (xevent->wParam)
+       {
+       case VK_LBUTTON:
+         event->key.keyval = GDK_Pointer_Button1; break;
+       case VK_RBUTTON:
+         event->key.keyval = GDK_Pointer_Button3; break;
+       case VK_MBUTTON:
+         event->key.keyval = GDK_Pointer_Button2; break;
+       case VK_CANCEL:
+         event->key.keyval = GDK_Cancel; break;
+       case VK_BACK:
+         event->key.keyval = GDK_BackSpace; break;
+       case VK_TAB:
+         event->key.keyval = GDK_Tab; break;
+       case VK_CLEAR:
+         event->key.keyval = GDK_Clear; break;
+       case VK_RETURN:
+         event->key.keyval = GDK_Return; break;
+       case VK_SHIFT:
+         event->key.keyval = GDK_Shift_L; break;
+       case VK_CONTROL:
+         if (xevent->lParam & 0x01000000)
+           event->key.keyval = GDK_Control_R;
+         else
+           event->key.keyval = GDK_Control_L;
+         break;
+       case VK_MENU:
+         if (xevent->lParam & 0x01000000)
+           {
+             /* AltGr key comes in as Control+Right Alt */
+             if (GetKeyState (VK_CONTROL) < 0)
+               {
+                 ignore_WM_CHAR = FALSE;
+                 is_AltGr_key = TRUE;
+               }
+             event->key.keyval = GDK_Alt_R;
+           }
+         else
+           event->key.keyval = GDK_Alt_L;
+         break;
+       case VK_PAUSE:
+         event->key.keyval = GDK_Pause; break;
+       case VK_CAPITAL:
+         event->key.keyval = GDK_Caps_Lock; break;
+       case VK_ESCAPE:
+         event->key.keyval = GDK_Escape; break;
+       case VK_PRIOR:
+         event->key.keyval = GDK_Prior; break;
+       case VK_NEXT:
+         event->key.keyval = GDK_Next; break;
+       case VK_END:
+         event->key.keyval = GDK_End; break;
+       case VK_HOME:
+         event->key.keyval = GDK_Home; break;
+       case VK_LEFT:
+         event->key.keyval = GDK_Left; break;
+       case VK_UP:
+         event->key.keyval = GDK_Up; break;
+       case VK_RIGHT:
+         event->key.keyval = GDK_Right; break;
+       case VK_DOWN:
+         event->key.keyval = GDK_Down; break;
+       case VK_SELECT:
+         event->key.keyval = GDK_Select; break;
+       case VK_PRINT:
+         event->key.keyval = GDK_Print; break;
+       case VK_EXECUTE:
+         event->key.keyval = GDK_Execute; break;
+       case VK_INSERT:
+         event->key.keyval = GDK_Insert; break;
+       case VK_DELETE:
+         event->key.keyval = GDK_Delete; break;
+       case VK_HELP:
+         event->key.keyval = GDK_Help; break;
+       case VK_NUMPAD0:
+       case VK_NUMPAD1:
+       case VK_NUMPAD2:
+       case VK_NUMPAD3:
+       case VK_NUMPAD4:
+       case VK_NUMPAD5:
+       case VK_NUMPAD6:
+       case VK_NUMPAD7:
+       case VK_NUMPAD8:
+       case VK_NUMPAD9:
+         /* Apparently applications work better if we just pass numpad digits
+          * on as real digits? So wait for the WM_CHAR instead.
+          */
+         ignore_WM_CHAR = FALSE;
+         break;
+       case VK_MULTIPLY:
+         event->key.keyval = GDK_KP_Multiply; break;
+       case VK_ADD:
+         event->key.keyval = GDK_KP_Add; break;
+       case VK_SEPARATOR:
+         event->key.keyval = GDK_KP_Separator; break;
+       case VK_SUBTRACT:
+         event->key.keyval = GDK_KP_Subtract; break;
+       case VK_DECIMAL:
+#if 0
+         event->key.keyval = GDK_KP_Decimal; break;
+#else
+         /* The keypad decimal key should also be passed on as the decimal
+          * sign ('.' or ',' depending on the Windows locale settings,
+          * apparently). So wait for the WM_CHAR here, also.
+          */
+         ignore_WM_CHAR = FALSE;
+         break;
+#endif
+       case VK_DIVIDE:
+         event->key.keyval = GDK_KP_Divide; break;
+       case VK_F1:
+         event->key.keyval = GDK_F1; break;
+       case VK_F2:
+         event->key.keyval = GDK_F2; break;
+       case VK_F3:
+         event->key.keyval = GDK_F3; break;
+       case VK_F4:
+         event->key.keyval = GDK_F4; break;
+       case VK_F5:
+         event->key.keyval = GDK_F5; break;
+       case VK_F6:
+         event->key.keyval = GDK_F6; break;
+       case VK_F7:
+         event->key.keyval = GDK_F7; break;
+       case VK_F8:
+         event->key.keyval = GDK_F8; break;
+       case VK_F9:
+         event->key.keyval = GDK_F9; break;
+       case VK_F10:
+         event->key.keyval = GDK_F10; break;
+       case VK_F11:
+         event->key.keyval = GDK_F11; break;
+       case VK_F12:
+         event->key.keyval = GDK_F12; break;
+       case VK_F13:
+         event->key.keyval = GDK_F13; break;
+       case VK_F14:
+         event->key.keyval = GDK_F14; break;
+       case VK_F15:
+         event->key.keyval = GDK_F15; break;
+       case VK_F16:
+         event->key.keyval = GDK_F16; break;
+       default:
+         if (xevent->message == WM_SYSKEYDOWN || xevent->message == WM_SYSKEYUP)
+           {
+             event->key.keyval = xevent->wParam;
+           }
+         else
+           {
+             ignore_WM_CHAR = FALSE;
+             event->key.keyval = GDK_VoidSymbol;
+           }
+         break;
+       }
+
+      if (!ignore_WM_CHAR)
+       break;
+
+      is_AltGr_key = FALSE;
+      event->key.type = ((xevent->message == WM_KEYDOWN
+                         | xevent->message == WM_SYSKEYDOWN) ?
+                        GDK_KEY_PRESS : GDK_KEY_RELEASE);
+      event->key.window = window;
+      event->key.time = xevent->time;
+      event->key.state = 0;
+      if (GetKeyState (VK_SHIFT) < 0)
+       event->key.state |= GDK_SHIFT_MASK;
+      if (GetKeyState (VK_CAPITAL) & 0x1)
+       event->key.state |= GDK_LOCK_MASK;
+      if (GetKeyState (VK_CONTROL) < 0)
+       event->key.state |= GDK_CONTROL_MASK;
+      if (xevent->wParam != VK_MENU && GetKeyState (VK_MENU) < 0)
+       event->key.state |= GDK_MOD1_MASK;
+      event->key.length = 0;
+      return_val = window_private && !window_private->destroyed;
+      event->key.string = NULL;
+      break;
+
+    case WM_CHAR:
+      GDK_NOTE (EVENTS, 
+               g_print ("WM_CHAR: %#x  char: %#x %#.08x  %s\n",
+                        xevent->hwnd,
+                        xevent->wParam,
+                        xevent->lParam,
+                        (ignore_WM_CHAR ? "ignored" : "")));
+
+      if (ignore_WM_CHAR)
+       {
+         ignore_WM_CHAR = FALSE;
+         break;
+       }
+
+    wm_char:
+      /* This doesn't handle the rather theorethical case that a window
+       * wants key presses but still wants releases to be propagated,
+       * for instance.
+       */
+      if (k_grab_window != NULL
+         && !k_grab_owner_events)
+       {
+         /* Keyboard is grabbed with owner_events FALSE */
+         GDK_NOTE (EVENTS,
+                   g_print ("grabbed, owner_events FALSE, "
+                            "sending to %#x\n", k_grab_window->xwindow));
+         event->key.window = (GdkWindow *) k_grab_window;
+       }
+      else if (window_private
+              && !(window_private->event_mask & (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK)))
+       {
+         /* Owner window doesn't want it */
+         if (k_grab_window != NULL
+             && k_grab_owner_events)
+           {
+             /* Keyboard is grabbed with owner_events TRUE */
+             GDK_NOTE (EVENTS,
+                       g_print ("grabbed, owner_events TRUE, doesn't want it, "
+                                "sending to %#x\n", k_grab_window->xwindow));
+             event->key.window = (GdkWindow *) k_grab_window;
+           }
+         else
+           {
+             /* Owner doesn't want it, neither is it grabbed, so
+              * propagate to parent.
+              */
+             if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+               g_assert_not_reached (); /* Should've been handled above */
+
+             gdk_window_unref (window);
+             window = window_private->parent;
+             gdk_window_ref (window);
+             window_private = (GdkWindowPrivate *) window;
+             GDK_NOTE (EVENTS,
+                       g_print ("not wanted, not grabbed, sending to %#x\n",
+                                window_private->xwindow));
+             goto wm_char;
+           }
+       }
+      
+      return_val = window_private && !window_private->destroyed;
+      if (return_val && (window_private->event_mask & GDK_KEY_RELEASE_MASK))
+       {
+         /* Return the release event, and maybe append the press
+          * event to the queued_events list (from which it will vbe
+          * fetched before the release event).
+          */
+         event->key.type = GDK_KEY_RELEASE;
+         event->key.keyval = xevent->wParam;
+         event->key.window = window;
+         event->key.time = xevent->time;
+         event->key.state = 0;
+         if (GetKeyState (VK_SHIFT) < 0)
+           event->key.state |= GDK_SHIFT_MASK;
+         if (GetKeyState (VK_CAPITAL) & 0x1)
+           event->key.state |= GDK_LOCK_MASK;
+         if (is_AltGr_key)
+           ;
+         else if (GetKeyState (VK_CONTROL) < 0)
+           {
+             event->key.state |= GDK_CONTROL_MASK;
+             if (event->key.keyval < ' ')
+               event->key.keyval += '@';
+           }
+         else if (event->key.keyval < ' ')
+           {
+             event->key.state |= GDK_CONTROL_MASK;
+             event->key.keyval += '@';
+           }
+         if (!is_AltGr_key && GetKeyState (VK_MENU) < 0)
+           event->key.state |= GDK_MOD1_MASK;
+         event->key.string = g_strdup (" ");
+         event->key.length = 1;
+         event->key.string[0] = xevent->wParam; /* ??? */
+
+         if (window_private->event_mask & GDK_KEY_PRESS_MASK)
+           {
+             /* Append also a GDK_KEY_PRESS event to the pushback list.  */
+             GdkEvent *event2 = gdk_event_copy (event);
+             event2->key.type = GDK_KEY_PRESS;
+             charcount = xevent->lParam & 0xFFFF;
+             if (charcount > sizeof (buf)- 1)
+               charcount = sizeof (buf) - 1;
+             g_free (event2->key.string);
+             event2->key.string = g_malloc (charcount);
+             for (i = 0; i < charcount; i++)
+               event2->key.string[i] = event->key.keyval;
+             event2->key.length = charcount;
+
+             gdk_event_queue_append (event2);
+           }
+       }
+      else if (return_val && (window_private->event_mask & GDK_KEY_PRESS_MASK))
+       {
+         /* Return just the GDK_KEY_PRESS event. */
+         event->key.type = GDK_KEY_PRESS;
+         charcount = xevent->lParam & 0xFFFF;
+         if (charcount > sizeof (buf)- 1)
+           charcount = sizeof (buf) - 1;
+         event->key.keyval = xevent->wParam;
+         event->key.window = window;
+         event->key.time = xevent->time;
+         event->key.state = 0;
+         if (GetKeyState (VK_SHIFT) < 0)
+           event->key.state |= GDK_SHIFT_MASK;
+         if (GetKeyState (VK_CAPITAL) & 0x1)
+           event->key.state |= GDK_LOCK_MASK;
+         if (is_AltGr_key)
+           ;
+         else if (GetKeyState (VK_CONTROL) < 0)
+           {
+             event->key.state |= GDK_CONTROL_MASK;
+             if (event->key.keyval < ' ')
+               event->key.keyval += '@';
+           }
+         else if (event->key.keyval < ' ')
+           {
+             event->key.state |= GDK_CONTROL_MASK;
+             event->key.keyval += '@';
+           }
+         if (!is_AltGr_key && GetKeyState (VK_MENU) < 0)
+           event->key.state |= GDK_MOD1_MASK;
+         event->key.string = g_malloc (charcount);
+         for (i = 0; i < charcount; i++)
+           event->key.string[i] = event->key.keyval;
+         event->key.length = charcount;
+       }
+      else
+       return_val = FALSE;
+      is_AltGr_key = FALSE;
+      break;
+
+    case WM_LBUTTONDOWN:
+      button = 1;
+      goto buttondown0;
+    case WM_MBUTTONDOWN:
+      button = 2;
+      goto buttondown0;
+    case WM_RBUTTONDOWN:
+      button = 3;
+
+      /* Print debugging info.
+       */
+    buttondown0:
+      GDK_NOTE (EVENTS, 
+               g_print ("WM_%cBUTTONDOWN: %#x  x,y: %d %d  button: %d\n",
+                        " LMR"[button],
+                        xevent->hwnd,
+                        LOWORD (xevent->lParam), HIWORD (xevent->lParam),
+                        button));
+
+      if (window_private
+         && (window_private->extension_events != 0)
+         && gdk_input_ignore_core)
+       {
+         GDK_NOTE (EVENTS, g_print ("... ignored\n"));
+         break;
+       }
+
+    buttondown:
+      event->button.type = GDK_BUTTON_PRESS;
+      event->button.window = window;
+      if (window_private)
+       mask = window_private->event_mask;
+      else
+       mask = 0;               /* ??? */
+
+      if (p_grab_window != NULL
+          && !p_grab_owner_events)
+       {
+         /* Pointer is grabbed with owner_events FALSE */
+         GDK_NOTE (EVENTS, g_print ("grabbed, owner_events FALSE\n"));
+         mask = p_grab_event_mask;
+         if (!(mask & GDK_BUTTON_PRESS_MASK))
+           /* Grabber doesn't want it */
+           break;
+         else
+           event->button.window = (GdkWindow *) p_grab_window;
+         GDK_NOTE (EVENTS, g_print ("sending to %#x\n",
+                                    p_grab_window->xwindow));
+       }
+      else if (window_private
+              && !(mask & GDK_BUTTON_PRESS_MASK))
+       {
+         /* Owner window doesn't want it */
+         if (p_grab_window != NULL
+             && p_grab_owner_events)
+           {
+             /* Pointer is grabbed wíth owner_events TRUE */ 
+             GDK_NOTE (EVENTS, g_print ("grabbed, owner_events TRUE, doesn't want it\n"));
+             mask = p_grab_event_mask;
+             if (!(mask & GDK_BUTTON_PRESS_MASK))
+               /* Grabber doesn't want it either */
+               break;
+             else
+               event->button.window = (GdkWindow *) p_grab_window;
+             GDK_NOTE (EVENTS, g_print ("sending to %#x\n",
+                                        p_grab_window->xwindow));
+           }
+         else
+           {
+             /* Owner doesn't want it, neither is it grabbed, so
+              * propagate to parent.
+              */
+             /* Yes, this code is duplicated twice below. So shoot me. */
+             if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+               break;
+             pt.x = LOWORD (xevent->lParam);
+             pt.y = HIWORD (xevent->lParam);
+             ClientToScreen (window_private->xwindow, &pt);
+             gdk_window_unref (window);
+             window = window_private->parent;
+             gdk_window_ref (window);
+             window_private = (GdkWindowPrivate *) window;
+             ScreenToClient (window_private->xwindow, &pt);
+             xevent->lParam = MAKELPARAM (pt.x, pt.y);
+             goto buttondown; /* What did Dijkstra say? */
+           }
+       }
+
+      /* Emulate X11's automatic active grab */
+      if (!p_grab_window)
+       {
+         /* No explicit active grab, let's start one automatically */
+         GDK_NOTE (EVENTS, g_print ("automatic grab started\n"));
+         gdk_pointer_grab (window, TRUE, window_private->event_mask,
+                           NULL, NULL, 0);
+         p_grab_automatic = TRUE;
+       }
+
+      if (window != curWnd)
+       synthesize_crossing_events (window, xevent);
+
+      event->button.time = xevent->time;
+      event->button.x = LOWORD (xevent->lParam);
+      event->button.y = HIWORD (xevent->lParam);
+      event->button.x_root = (gfloat)xevent->pt.x;
+      event->button.y_root = (gfloat)xevent->pt.y;
+      event->button.pressure = 0.5;
+      event->button.xtilt = 0;
+      event->button.ytilt = 0;
+      event->button.state = 0;
+      if (xevent->wParam & MK_CONTROL)
+       event->button.state |= GDK_CONTROL_MASK;
+      if (xevent->wParam & MK_LBUTTON)
+       event->button.state |= GDK_BUTTON1_MASK;
+      if (xevent->wParam & MK_MBUTTON)
+       event->button.state |= GDK_BUTTON2_MASK;
+      if (xevent->wParam & MK_RBUTTON)
+       event->button.state |= GDK_BUTTON3_MASK;
+      if (xevent->wParam & MK_SHIFT)
+       event->button.state |= GDK_SHIFT_MASK;
+      if (GetKeyState (VK_MENU) < 0)
+       event->button.state |= GDK_MOD1_MASK;
+      if (GetKeyState (VK_CAPITAL) & 0x1)
+       event->button.state |= GDK_LOCK_MASK;
+      event->button.button = button;
+      event->button.source = GDK_SOURCE_MOUSE;
+      event->button.deviceid = GDK_CORE_POINTER;
+
+      if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
+         (event->button.window == button_window[1]) &&
+         (event->button.button == button_number[1]))
+       {
+         gdk_synthesize_click (event, 3);
+
+         button_click_time[1] = 0;
+         button_click_time[0] = 0;
+         button_window[1] = NULL;
+         button_window[0] = 0;
+         button_number[1] = -1;
+         button_number[0] = -1;
+       }
+      else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
+              (event->button.window == button_window[0]) &&
+              (event->button.button == button_number[0]))
+       {
+         gdk_synthesize_click (event, 2);
+
+         button_click_time[1] = button_click_time[0];
+         button_click_time[0] = event->button.time;
+         button_window[1] = button_window[0];
+         button_window[0] = event->button.window;
+         button_number[1] = button_number[0];
+         button_number[0] = event->button.button;
+       }
+      else
+       {
+         button_click_time[1] = 0;
+         button_click_time[0] = event->button.time;
+         button_window[1] = NULL;
+         button_window[0] = event->button.window;
+         button_number[1] = -1;
+         button_number[0] = event->button.button;
+       }
+      return_val = window_private && !window_private->destroyed;
+      if (return_val
+         && p_grab_window != NULL
+         && event->any.window == (GdkWindow *) p_grab_window
+         && p_grab_window != window_private)
+       {
+         /* Translate coordinates to grabber */
+         pt.x = event->button.x;
+         pt.y = event->button.y;
+         ClientToScreen (window_private->xwindow, &pt);
+         ScreenToClient (p_grab_window->xwindow, &pt);
+         event->button.x = pt.x;
+         event->button.y = pt.y;
+         GDK_NOTE (EVENTS, g_print ("New coords are +%d+%d\n", pt.x, pt.y));
+       }
+      break;
+
+    case WM_LBUTTONUP:
+      button = 1;
+      goto buttonup0;
+    case WM_MBUTTONUP:
+      button = 2;
+      goto buttonup0;
+    case WM_RBUTTONUP:
+      button = 3;
+
+      /* Print debugging info.
+       */
+    buttonup0:
+      GDK_NOTE (EVENTS, 
+               g_print ("WM_%cBUTTONUP: %#x  x,y: %d %d  button: %d\n",
+                        " LMR"[button],
+                        xevent->hwnd,
+                        LOWORD (xevent->lParam), HIWORD (xevent->lParam),
+                        button));
+
+      if (window_private
+         && (window_private->extension_events != 0)
+         && gdk_input_ignore_core)
+       {
+         GDK_NOTE (EVENTS, g_print ("... ignored\n"));
+         break;
+       }
+
+    buttonup:
+      event->button.type = GDK_BUTTON_RELEASE;
+      event->button.window = window;
+      if (window_private)
+       mask = window_private->event_mask;
+      else
+       mask = 0;
+
+      if (p_grab_window != NULL
+          && !p_grab_owner_events)
+       {
+         /* Pointer is grabbed with owner_events FALSE */
+         GDK_NOTE (EVENTS, g_print ("grabbed, owner_events FALSE\n"));
+         mask = p_grab_event_mask;
+         if (!(mask & GDK_BUTTON_RELEASE_MASK))
+           /* Grabber doesn't want it */
+           break;
+         else
+           event->button.window = (GdkWindow *) p_grab_window;
+         GDK_NOTE (EVENTS, g_print ("sending to %#x\n",
+                                    p_grab_window->xwindow));
+       }
+      else if (window_private
+              && !(mask & GDK_BUTTON_RELEASE_MASK))
+       {
+         /* Owner window doesn't want it */
+         if (p_grab_window != NULL
+             && p_grab_owner_events)
+           {
+             /* Pointer is grabbed wíth owner_events TRUE */
+             GDK_NOTE (EVENTS, g_print ("grabbed, owner_events TRUE, doesn't want it\n"));
+             mask = p_grab_event_mask;
+             if (!(mask & GDK_BUTTON_RELEASE_MASK))
+               /* Grabber doesn't want it */
+               break;
+             else
+               event->button.window = (GdkWindow *) p_grab_window;
+             GDK_NOTE (EVENTS, g_print ("sending to %#x\n",
+                                        p_grab_window->xwindow));
+           }
+         else
+           {
+             /* Owner doesn't want it, neither is it grabbed, so
+              * propagate to parent.
+              */
+             if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+               break;
+             pt.x = LOWORD (xevent->lParam);
+             pt.y = HIWORD (xevent->lParam);
+             ClientToScreen (window_private->xwindow, &pt);
+             gdk_window_unref (window);
+             window = window_private->parent;
+             gdk_window_ref (window);
+             window_private = (GdkWindowPrivate *) window;
+             ScreenToClient (window_private->xwindow, &pt);
+             xevent->lParam = MAKELPARAM (pt.x, pt.y);
+             goto buttonup;
+           }
+       }
+
+      if (window != curWnd)
+       synthesize_crossing_events (window, xevent);
+
+      event->button.time = xevent->time;
+      event->button.x = LOWORD (xevent->lParam);
+      event->button.y = HIWORD (xevent->lParam);
+      event->button.x_root = (gfloat)xevent->pt.x;
+      event->button.y_root = (gfloat)xevent->pt.y;
+      event->button.pressure = 0.5;
+      event->button.xtilt = 0;
+      event->button.ytilt = 0;
+      event->button.state = 0;
+      if (xevent->wParam & MK_CONTROL)
+       event->button.state |= GDK_CONTROL_MASK;
+      if (xevent->wParam & MK_LBUTTON)
+       event->button.state |= GDK_BUTTON1_MASK;
+      if (xevent->wParam & MK_MBUTTON)
+       event->button.state |= GDK_BUTTON2_MASK;
+      if (xevent->wParam & MK_RBUTTON)
+       event->button.state |= GDK_BUTTON3_MASK;
+      if (xevent->wParam & MK_SHIFT)
+       event->button.state |= GDK_SHIFT_MASK;
+      event->button.button = button;
+      event->button.source = GDK_SOURCE_MOUSE;
+      event->button.deviceid = GDK_CORE_POINTER;
+      return_val = window_private && !window_private->destroyed;
+      if (return_val
+         && p_grab_window != NULL
+         && event->any.window == (GdkWindow *) p_grab_window
+         && p_grab_window != window_private)
+       {
+         /* Translate coordinates to grabber */
+         pt.x = event->button.x;
+         pt.y = event->button.y;
+         ClientToScreen (window_private->xwindow, &pt);
+         ScreenToClient (p_grab_window->xwindow, &pt);
+         event->button.x = pt.x;
+         event->button.y = pt.y;
+         GDK_NOTE (EVENTS, g_print ("New coords are +%d+%d\n", pt.x, pt.y));
+       }
+      if (p_grab_window != NULL
+         && p_grab_automatic
+         && (event->button.state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) == 0)
+       gdk_pointer_ungrab (0);
+      break;
+
+    case WM_MOUSEMOVE:
+      /* Print debugging info.
+       */
+      GDK_NOTE (EVENTS,
+               g_print ("WM_MOUSEMOVE: %#x  %#x +%d+%d\n",
+                        xevent->hwnd, xevent->wParam,
+                        LOWORD (xevent->lParam), HIWORD (xevent->lParam)));
+
+#if 0
+      /* Try hard not to generate events for windows that shouldn't
+        get any.  This is hard because we don't want pushbuttons to
+        highlight when the cursor moves over them if the window is
+        inactive. We dont want tooltips windows to be active. OTOH,
+        also menus are popup windows, but they definitely should
+        get events. Aw shit. Skip this.
+       */
+      dwStyle = GetWindowLong (xevent->hwnd, GWL_STYLE);
+      if (active == NULL ||
+         !(active == xevent->hwnd
+           || (dwStyle & WS_POPUP)
+           || IsChild (active, xevent->hwnd)))
+       break;
+#else
+      { /* HB: only process mouse move messages
+         * if we own the active window.
+         */
+         DWORD ProcessID_ActWin;
+         DWORD ProcessID_this;
+
+         GetWindowThreadProcessId(GetActiveWindow(), &ProcessID_ActWin);
+         GetWindowThreadProcessId(xevent->hwnd, &ProcessID_this);
+         if (ProcessID_ActWin != ProcessID_this)
+          break;
+     }
+#endif
+      if (window != curWnd)
+       synthesize_crossing_events (window, xevent);
+
+      if (window_private
+         && (window_private->extension_events != 0)
+         && gdk_input_ignore_core)
+       {
+         GDK_NOTE (EVENTS, g_print ("... ignored\n"));
+         break;
+       }
+
+    mousemotion:
+      event->motion.type = GDK_MOTION_NOTIFY;
+      event->motion.window = window;
+      if (window_private)
+       mask = window_private->event_mask;
+      else
+       mask = 0;
+
+      if (p_grab_window
+         && !p_grab_owner_events)
+       {
+         /* Pointer is grabbed with owner_events FALSE */
+         GDK_NOTE (EVENTS,
+                   g_print ("grabbed, owner_events FALSE\n"));
+         mask = p_grab_event_mask;
+         if (!((mask & GDK_POINTER_MOTION_MASK)
+               || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))
+                   && (mask & GDK_BUTTON_MOTION_MASK))
+               || ((xevent->wParam & MK_LBUTTON)
+                   && (mask & GDK_BUTTON1_MOTION_MASK))
+               || ((xevent->wParam & MK_MBUTTON)
+                   && (mask & GDK_BUTTON2_MOTION_MASK))
+               || ((xevent->wParam & MK_RBUTTON)
+                   && (mask & GDK_BUTTON3_MOTION_MASK))))
+           break;
+         else
+           event->motion.window = (GdkWindow *) p_grab_window;
+         GDK_NOTE (EVENTS, g_print ("sending to %#x\n",
+                                    p_grab_window->xwindow));
+       }
+      else if (window_private
+              && !((mask & GDK_POINTER_MOTION_MASK)
+                   || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))
+                       && (mask & GDK_BUTTON_MOTION_MASK))
+                   || ((xevent->wParam & MK_LBUTTON)
+                       && (mask & GDK_BUTTON1_MOTION_MASK))
+                   || ((xevent->wParam & MK_MBUTTON)
+                       && (mask & GDK_BUTTON2_MOTION_MASK))
+                   || ((xevent->wParam & MK_RBUTTON)
+                       && (mask & GDK_BUTTON3_MOTION_MASK))))
+       {
+         /* Owner window doesn't want it */
+         if (p_grab_window != NULL
+             && p_grab_owner_events)
+           {
+             /* Pointer is grabbed wíth owner_events TRUE */
+             GDK_NOTE (EVENTS, g_print ("grabbed, owner_events TRUE, doesn't want it\n"));
+             mask = p_grab_event_mask;
+             if (!((p_grab_event_mask & GDK_POINTER_MOTION_MASK)
+                   || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))
+                       && (mask & GDK_BUTTON_MOTION_MASK))
+                   || ((xevent->wParam & MK_LBUTTON)
+                       && (mask & GDK_BUTTON1_MOTION_MASK))
+                   || ((xevent->wParam & MK_MBUTTON)
+                       && (mask & GDK_BUTTON2_MOTION_MASK))
+                   || ((xevent->wParam & MK_RBUTTON)
+                       && (mask & GDK_BUTTON3_MOTION_MASK))))
+               /* Grabber doesn't want it either */
+               break;
+             else
+               event->motion.window = (GdkWindow *) p_grab_window;
+             GDK_NOTE (EVENTS, g_print ("sending to %#x\n",
+                                        p_grab_window->xwindow));
+           }
+         else
+           {
+             /* Owner doesn't want it, neither is it grabbed, so
+              * propagate to parent.
+              */
+             if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+               break;
+             pt.x = LOWORD (xevent->lParam);
+             pt.y = HIWORD (xevent->lParam);
+             ClientToScreen (window_private->xwindow, &pt);
+             gdk_window_unref (window);
+             window = window_private->parent;
+             gdk_window_ref (window);
+             window_private = (GdkWindowPrivate *) window;
+             ScreenToClient (window_private->xwindow, &pt);
+             xevent->lParam = MAKELPARAM (pt.x, pt.y);
+             GDK_NOTE (EVENTS, g_print ("propagating to %#x\n",
+                                        window_private->xwindow));
+             goto mousemotion;
+           }
+       }
+
+      event->motion.time = xevent->time;
+      event->motion.x = curX = LOWORD (xevent->lParam);
+      event->motion.y = curY = HIWORD (xevent->lParam);
+      event->motion.x_root = xevent->pt.x;
+      event->motion.y_root = xevent->pt.y;
+      curXroot = event->motion.x_root;
+      curYroot = event->motion.y_root;
+      event->motion.pressure = 0.5;
+      event->motion.xtilt = 0;
+      event->motion.ytilt = 0;
+      event->button.state = 0;
+      if (xevent->wParam & MK_CONTROL)
+       event->button.state |= GDK_CONTROL_MASK;
+      if (xevent->wParam & MK_LBUTTON)
+       event->button.state |= GDK_BUTTON1_MASK;
+      if (xevent->wParam & MK_MBUTTON)
+       event->button.state |= GDK_BUTTON2_MASK;
+      if (xevent->wParam & MK_RBUTTON)
+       event->button.state |= GDK_BUTTON3_MASK;
+      if (xevent->wParam & MK_SHIFT)
+       event->button.state |= GDK_SHIFT_MASK;
+      if (mask & GDK_POINTER_MOTION_HINT_MASK)
+       event->motion.is_hint = NotifyHint;
+      else
+       event->motion.is_hint = NotifyNormal;
+      event->motion.source = GDK_SOURCE_MOUSE;
+      event->motion.deviceid = GDK_CORE_POINTER;
+
+      return_val = window_private && !window_private->destroyed;
+      if (return_val
+         && p_grab_window != NULL
+         && event->any.window == (GdkWindow *) p_grab_window
+         && p_grab_window != window_private)
+       {
+         /* Translate coordinates to grabber */
+         pt.x = event->motion.x;
+         pt.y = event->motion.y;
+         ClientToScreen (window_private->xwindow, &pt);
+         ScreenToClient (p_grab_window->xwindow, &pt);
+         event->motion.x = pt.x;
+         event->motion.y = pt.y;
+         GDK_NOTE (EVENTS, g_print ("New coords are +%d+%d\n", pt.x, pt.y));
+       }
+      break;
+
+    case WM_NCMOUSEMOVE:
+      /* Print debugging info.  */
+      GDK_NOTE (EVENTS,
+               g_print ("WM_NCMOUSEMOVE: %#x  x,y: %d %d\n",
+                        xevent->hwnd,
+                        LOWORD (xevent->lParam), HIWORD (xevent->lParam)));
+#if 0
+      if (active == NULL || active != xevent->hwnd)
+       break;
+#endif
+      curWnd_private = (GdkWindowPrivate *) curWnd;
+      if (curWnd != NULL
+         && (curWnd_private->event_mask & GDK_LEAVE_NOTIFY_MASK))
+       {
+         GDK_NOTE (EVENTS, g_print ("synthesizing LEAVE_NOTIFY event\n"));
+
+         event->crossing.type = GDK_LEAVE_NOTIFY;
+         event->crossing.window = curWnd;
+         event->crossing.subwindow = NULL;
+         event->crossing.time = xevent->time;
+         event->crossing.x = curX;
+         event->crossing.y = curY;
+         event->crossing.x_root = curXroot;
+         event->crossing.y_root = curYroot;
+         event->crossing.mode = GDK_CROSSING_NORMAL;
+         event->crossing.detail = GDK_NOTIFY_UNKNOWN;
+
+         event->crossing.focus = TRUE; /* ??? */
+         event->crossing.state = 0; /* ??? */
+         gdk_window_unref (curWnd);
+         curWnd = NULL;
+
+         return_val = TRUE;
+       }
+      break;
+
+    case WM_SETFOCUS:
+    case WM_KILLFOCUS:
+      if (window_private
+         && !(window_private->event_mask & GDK_FOCUS_CHANGE_MASK))
+       break;
+
+      GDK_NOTE (EVENTS, g_print ("WM_%sFOCUS: %#x\n",
+                                (xevent->message == WM_SETFOCUS ? "SET" : "KILL"),
+                                xevent->hwnd));
+      
+      event->focus_change.type = GDK_FOCUS_CHANGE;
+      event->focus_change.window = window;
+      event->focus_change.in = (xevent->message == WM_SETFOCUS);
+      return_val = window_private && !window_private->destroyed;
+      break;
+#if 0
+    case WM_ACTIVATE:
+      GDK_NOTE (EVENTS, g_print ("WM_ACTIVATE: %#x  %d\n",
+                                xevent->hwnd, LOWORD (xevent->wParam)));
+      if (LOWORD (xevent->wParam) == WA_INACTIVE)
+       active = (HWND) xevent->lParam;
+      else
+       active = xevent->hwnd;
+      break;
+#endif
+    case WM_ERASEBKGND:
+      GDK_NOTE (EVENTS, g_print ("WM_ERASEBKGND: %#x  dc %#x\n",
+                                xevent->hwnd, xevent->wParam));
+      
+      if (!window_private || window_private->destroyed)
+       break;
+      colormap_private = (GdkColormapPrivate *) window_private->colormap;
+      hdc = (HDC) xevent->wParam;
+      if (colormap_private
+         && colormap_private->xcolormap->rc_palette)
+       {
+         int k;
+
+         if (SelectPalette (hdc,  colormap_private->xcolormap->palette,
+                            FALSE) == NULL)
+           g_warning ("WM_ERASEBKGND: SelectPalette failed");
+         if ((k = RealizePalette (hdc)) == GDI_ERROR)
+           g_warning ("WM_ERASEBKGND: RealizePalette failed");
+#if 0
+         g_print ("WM_ERASEBKGND: selected %#x, realized %d colors\n",
+                  colormap_private->xcolormap->palette, k);
+#endif
+       }
+      *ret_val_flagp = TRUE;
+      *ret_valp = 1;
+
+      if (window_private->bg_type == GDK_WIN32_BG_TRANSPARENT)
+       break;
+
+      if (window_private->bg_type == GDK_WIN32_BG_PARENT_RELATIVE)
+       {
+         /* If this window should have the same background as the
+          * parent, fetch the parent. (And if the same goes for
+          * the parent, fetch the grandparent, etc.)
+          */
+         while (window_private
+                && window_private->bg_type == GDK_WIN32_BG_PARENT_RELATIVE)
+           window_private = (GdkWindowPrivate *) window_private->parent;
+       }
+
+      if (window_private->bg_type == GDK_WIN32_BG_PIXEL)
+       {
+         COLORREF bg;
+         GDK_NOTE (EVENTS, g_print ("... BG_PIXEL %s\n",
+                                    gdk_color_to_string (&window_private->bg_pixel)));
+         GetClipBox (hdc, &rect);
+#ifdef MULTIPLE_WINDOW_CLASSES
+         bg = PALETTEINDEX (window_private->bg_pixel.pixel);
+#else
+         bg = GetNearestColor (hdc, RGB (window_private->bg_pixel.red >> 8,
+                                         window_private->bg_pixel.green >> 8,
+                                         window_private->bg_pixel.blue >> 8));
+#endif
+         hbr = CreateSolidBrush (bg);
+#if 0
+         g_print ("... CreateSolidBrush (%.08x) = %.08x\n", bg, hbr);
+#endif
+         if (!FillRect (hdc, &rect, hbr))
+           g_warning ("WM_ERASEBKGND: FillRect failed");
+         DeleteObject (hbr);
+       }
+      else if (window_private->bg_type == GDK_WIN32_BG_PIXMAP)
+       {
+         GdkPixmapPrivate *pixmap_private;
+         HDC bgdc;
+         HGDIOBJ oldbitmap;
+
+         pixmap_private = (GdkPixmapPrivate *) window_private->bg_pixmap;
+         GetClipBox (hdc, &rect);
+
+         if (pixmap_private->width <= 8
+             && pixmap_private->height <= 8)
+           {
+             GDK_NOTE (EVENTS, g_print ("...small pixmap, using brush\n"));
+             hbr = CreatePatternBrush (pixmap_private->xwindow);
+             if (!FillRect (hdc, &rect, hbr))
+               g_warning ("WM_ERASEBKGND: FillRect failed");
+             DeleteObject (hbr);
+           }
+         else
+           {
+             GDK_NOTE (EVENTS,
+                       g_print ("...blitting pixmap %#x (%dx%d) "
+                                "all over the place,\n"
+                                "...clip box = %dx%d@+%d+%d\n",
+                                pixmap_private->xwindow,
+                                pixmap_private->width, pixmap_private->height,
+                                rect.right - rect.left, rect.bottom - rect.top,
+                                rect.left, rect.top));
+
+             if (!(bgdc = CreateCompatibleDC (hdc)))
+               {
+                 g_warning ("WM_ERASEBKGND: CreateCompatibleDC failed");
+                 break;
+               }
+             if (!(oldbitmap = SelectObject (bgdc, pixmap_private->xwindow)))
+               {
+                 g_warning ("WM_ERASEBKGND: SelectObject failed");
+                 DeleteDC (bgdc);
+                 break;
+               }
+             i = 0;
+             while (i < rect.right)
+               {
+                 j = 0;
+                 while (j < rect.bottom)
+                   {
+                     if (i + pixmap_private->width >= rect.left
+                         && j + pixmap_private->height >= rect.top)
+                       {
+                         if (!BitBlt (hdc, i, j,
+                                      pixmap_private->width, pixmap_private->height,
+                                      bgdc, 0, 0, SRCCOPY))
+                           {
+                             g_warning ("WM_ERASEBKGND: BitBlt failed");
+                             goto loopexit;
+                           }
+                       }
+                     j += pixmap_private->height;
+                   }
+                 i += pixmap_private->width;
+               }
+           loopexit:
+             SelectObject (bgdc, oldbitmap);
+             DeleteDC (bgdc);
+           }
+       }
+      else
+       {
+         GDK_NOTE (EVENTS, g_print ("... BLACK_BRUSH (?)\n"));
+#ifdef MULTIPLE_WINDOW_CLASSES
+         hbr = (HBRUSH) GetClassLong (window_private->xwindow,
+                                      GCL_HBRBACKGROUND);
+#else
+         hbr = GetStockObject (BLACK_BRUSH);
+#endif
+         GetClipBox (hdc, &rect);
+         if (!FillRect (hdc, &rect, hbr))
+           g_warning ("WM_ERASEBKGND: FillRect failed");
+       }
+      break;
+
+    case WM_PAINT:
+      GDK_NOTE (EVENTS, g_print ("WM_PAINT: %#x\n", xevent->hwnd));
+      hdc = BeginPaint (xevent->hwnd, &paintstruct);
+
+      /* Print debugging info.
+       */
+      GDK_NOTE (EVENTS,
+               g_print ("...WM_PAINT: %#x  %dx%d@+%d+%d %s dc %#x\n",
+                        xevent->hwnd,
+                        paintstruct.rcPaint.right - paintstruct.rcPaint.left,
+                        paintstruct.rcPaint.bottom - paintstruct.rcPaint.top,
+                        paintstruct.rcPaint.left, paintstruct.rcPaint.top,
+                        (paintstruct.fErase ? "erase" : ""),
+                        hdc));
+
+      EndPaint (xevent->hwnd, &paintstruct);
+
+      if (window_private
+         && !(window_private->event_mask & GDK_EXPOSURE_MASK))
+       break;
+
+      event->expose.type = GDK_EXPOSE;
+      event->expose.window = window;
+      event->expose.area.x = paintstruct.rcPaint.left;
+      event->expose.area.y = paintstruct.rcPaint.top;
+      event->expose.area.width = paintstruct.rcPaint.right - paintstruct.rcPaint.left;
+      event->expose.area.height = paintstruct.rcPaint.bottom - paintstruct.rcPaint.top;
+      event->expose.count = 1;
+
+      return_val = window_private && !window_private->destroyed;
+      break;
+
+#ifndef MULTIPLE_WINDOW_CLASSES
+    case WM_SETCURSOR:
+      GDK_NOTE (EVENTS, g_print ("WM_SETCURSOR: %#x %#x %#x\n",
+                                xevent->hwnd,
+                                LOWORD (xevent->lParam), HIWORD (xevent->lParam)));
+
+      return_val = FALSE;
+      if (LOWORD (xevent->lParam) != HTCLIENT)
+       break;
+      if (p_grab_window != NULL && p_grab_cursor != NULL)
+       SetCursor (p_grab_cursor);
+      else if (window_private
+              && !window_private->destroyed
+              && window_private->xcursor)
+       SetCursor (window_private->xcursor);
+      *ret_val_flagp = TRUE;
+      *ret_valp = FALSE;
+      break;
+#endif
+
+#if 0
+    case WM_QUERYOPEN:
+      GDK_NOTE (EVENTS, g_print ("WM_QUERYOPEN: %#x\n",
+                                xevent->hwnd));
+      *ret_val_flagp = TRUE;
+      *ret_valp = TRUE;
+
+      if (window_private
+         && !(window_private->event_mask & GDK_STRUCTURE_MASK))
+       break;
+
+      event->any.type = GDK_MAP;
+      event->any.window = window;
+
+      return_val = window_private && !window_private->destroyed;
+      break;
+#endif
+
+#if 1
+    case WM_SHOWWINDOW:
+      /* Print debugging info.
+       */
+      GDK_NOTE (EVENTS, g_print ("WM_SHOWWINDOW: %#x  %d\n",
+                                xevent->hwnd,
+                                xevent->wParam));
+
+      if (window_private
+         && !(window_private->event_mask & GDK_STRUCTURE_MASK))
+       break;
+
+      event->any.type = (xevent->wParam ? GDK_MAP : GDK_UNMAP);
+      event->any.window = window;
+
+      if (event->any.type == GDK_UNMAP
+         && p_grab_window == window_private)
+       gdk_pointer_ungrab (xevent->time);
+
+      if (event->any.type == GDK_UNMAP
+         && k_grab_window == window_private)
+       gdk_keyboard_ungrab (xevent->time);
+
+      return_val = window_private && !window_private->destroyed;
+      break;
+#endif
+    case WM_SIZE:
+      /* Print debugging info.
+       */
+      GDK_NOTE (EVENTS,
+               g_print ("WM_SIZE: %#x  %s %dx%d\n",
+                        xevent->hwnd,
+                        (xevent->wParam == SIZE_MAXHIDE ? "MAXHIDE" :
+                         (xevent->wParam == SIZE_MAXIMIZED ? "MAXIMIZED" :
+                          (xevent->wParam == SIZE_MAXSHOW ? "MAXSHOW" :
+                           (xevent->wParam == SIZE_MINIMIZED ? "MINIMIZED" :
+                            (xevent->wParam == SIZE_RESTORED ? "RESTORED" : "?"))))),
+                        LOWORD (xevent->lParam), HIWORD (xevent->lParam)));
+
+      if (window_private
+         && !(window_private->event_mask & GDK_STRUCTURE_MASK))
+       break;
+      if (window_private != NULL
+         && xevent->wParam == SIZE_MINIMIZED)
+       {
+#if 1
+         event->any.type = GDK_UNMAP;
+         event->any.window = window;
+
+         if (p_grab_window == window_private)
+           gdk_pointer_ungrab (xevent->time);
+
+         if (k_grab_window == window_private)
+           gdk_keyboard_ungrab (xevent->time);
+
+         return_val = !window_private->destroyed;
+#endif
+       }
+      else if (window_private != NULL
+              && (xevent->wParam == SIZE_RESTORED
+                  || xevent->wParam == SIZE_MAXIMIZED)
+#if 1
+              && window_private->window_type != GDK_WINDOW_CHILD
+#endif
+                                                                )
+       {
+         if (LOWORD (xevent->lParam) == 0)
+           break;
+
+         event->configure.type = GDK_CONFIGURE;
+         event->configure.window = window;
+         pt.x = 0;
+         pt.y = 0;
+         ClientToScreen (xevent->hwnd, &pt);
+         event->configure.x = pt.x;
+         event->configure.y = pt.y;
+         event->configure.width = LOWORD (xevent->lParam);
+         event->configure.height = HIWORD (xevent->lParam);
+         window_private->x = event->configure.x;
+         window_private->y = event->configure.y;
+         window_private->width = event->configure.width;
+         window_private->height = event->configure.height;
+         if (window_private->resize_count > 1)
+           window_private->resize_count -= 1;
+         
+         return_val = !window_private->destroyed;
+         if (return_val
+             && window_private->extension_events != 0
+             && gdk_input_vtable.configure_event)
+           gdk_input_vtable.configure_event (&event->configure, window);
+       }
+      break;
+
+    case WM_SIZING:
+      GDK_NOTE (EVENTS, g_print ("WM_SIZING: %#x\n", xevent->hwnd));
+      if (ret_val_flagp == NULL)
+         g_warning ("ret_val_flagp is NULL but we got a WM_SIZING?");
+      else if (window_private != NULL
+              && window_private->hint_flags &
+              (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE))
+       {
+         LPRECT lprc = (LPRECT) xevent->lParam;
+
+         if (window_private->hint_flags & GDK_HINT_MIN_SIZE)
+           {
+             gint w = lprc->right - lprc->left;
+             gint h = lprc->bottom - lprc->top;
+
+             if (w < window_private->hint_min_width)
+               {
+                 if (xevent->wParam == WMSZ_BOTTOMLEFT
+                     || xevent->wParam == WMSZ_LEFT
+                     || xevent->wParam == WMSZ_TOPLEFT)
+                   lprc->left = lprc->right - window_private->hint_min_width;
+                 else
+                   lprc->right = lprc->left + window_private->hint_min_width;
+                 *ret_val_flagp = TRUE;
+                 *ret_valp = TRUE;
+               }
+             if (h < window_private->hint_min_height)
+               {
+                 if (xevent->wParam == WMSZ_BOTTOMLEFT
+                     || xevent->wParam == WMSZ_BOTTOM
+                     || xevent->wParam == WMSZ_BOTTOMRIGHT)
+                   lprc->bottom = lprc->top + window_private->hint_min_height;
+                 else
+                   lprc->top = lprc->bottom - window_private->hint_min_height;
+                 *ret_val_flagp = TRUE;
+                 *ret_valp = TRUE;
+               }
+           }
+         if (window_private->hint_flags & GDK_HINT_MAX_SIZE)
+           {
+             gint w = lprc->right - lprc->left;
+             gint h = lprc->bottom - lprc->top;
+
+             if (w > window_private->hint_max_width)
+               {
+                 if (xevent->wParam == WMSZ_BOTTOMLEFT
+                     || xevent->wParam == WMSZ_LEFT
+                     || xevent->wParam == WMSZ_TOPLEFT)
+                   lprc->left = lprc->right - window_private->hint_max_width;
+                 else
+                   lprc->right = lprc->left + window_private->hint_max_width;
+                 *ret_val_flagp = TRUE;
+                 *ret_valp = TRUE;
+               }
+             if (h > window_private->hint_max_height)
+               {
+                 if (xevent->wParam == WMSZ_BOTTOMLEFT
+                     || xevent->wParam == WMSZ_BOTTOM
+                     || xevent->wParam == WMSZ_BOTTOMRIGHT)
+                   lprc->bottom = lprc->top + window_private->hint_max_height;
+                 else
+                   lprc->top = lprc->bottom - window_private->hint_max_height;
+                 *ret_val_flagp = TRUE;
+                 *ret_valp = TRUE;
+               }
+           }
+       }
+      break;
+
+    case WM_MOVE:
+      GDK_NOTE (EVENTS, g_print ("WM_MOVE: %#x  +%d+%d\n",
+                                xevent->hwnd,
+                                LOWORD (xevent->lParam), HIWORD (xevent->lParam)));
+
+      if (window_private
+         && !(window_private->event_mask & GDK_STRUCTURE_MASK))
+       break;
+      if (window_private != NULL
+         && window_private->window_type != GDK_WINDOW_CHILD)
+       {
+         event->configure.type = GDK_CONFIGURE;
+         event->configure.window = window;
+         event->configure.x = LOWORD (xevent->lParam);
+         event->configure.y = HIWORD (xevent->lParam);
+         GetClientRect (xevent->hwnd, &rect);
+         event->configure.width = rect.right;
+         event->configure.height = rect.bottom;
+         window_private->x = event->configure.x;
+         window_private->y = event->configure.y;
+         window_private->width = event->configure.width;
+         window_private->height = event->configure.height;
+         
+         return_val = !window_private->destroyed;
+       }
+      break;
+
+    case WM_CLOSE:
+      GDK_NOTE (EVENTS, g_print ("WM_CLOSE: %#x\n", xevent->hwnd));
+      event->any.type = GDK_DELETE;
+      event->any.window = window;
+      
+      return_val = window_private && !window_private->destroyed;
+      break;
+
+#if 0
+    /* No, don't use delayed rendering after all. It works only if the
+     * delayed SetClipboardData is called from the WindowProc, it
+     * seems. (The #else part below is test code for that. It succeeds
+     * in setting the clipboard data. But if I call SetClipboardData
+     * in gdk_property_change (as a consequence of the
+     * GDK_SELECTION_REQUEST event), it fails.  I deduce that this is
+     * because delayed rendering requires that SetClipboardData is
+     * called in the window procedure.)
+     */
+    case WM_RENDERFORMAT:
+    case WM_RENDERALLFORMATS:
+      flag = FALSE;
+      GDK_NOTE (EVENTS, flag = TRUE);
+      GDK_NOTE (SELECTION, flag = TRUE);
+      if (flag)
+       g_print ("WM_%s: %#x %#x (%s)\n",
+                (xevent->message == WM_RENDERFORMAT ? "RENDERFORMAT" :
+                 "RENDERALLFORMATS"),
+                xevent->hwnd,
+                xevent->wParam,
+                (xevent->wParam == CF_TEXT ? "CF_TEXT" :
+                 (xevent->wParam == CF_DIB ? "CF_DIB" :
+                  (xevent->wParam == CF_UNICODETEXT ? "CF_UNICODETEXT" :
+                   (GetClipboardFormatName (xevent->wParam, buf, sizeof (buf)), buf)))));
+
+#if 0
+      event->selection.type = GDK_SELECTION_REQUEST;
+      event->selection.window = window;
+      event->selection.selection = gdk_clipboard_atom;
+      if (xevent->wParam == CF_TEXT)
+       event->selection.target = GDK_TARGET_STRING;
+      else
+       {
+         GetClipboardFormatName (xevent->wParam, buf, sizeof (buf));
+         event->selection.target = gdk_atom_intern (buf, FALSE);
+       }
+      event->selection.property = gdk_selection_property;
+      event->selection.requestor = (guint32) xevent->hwnd;
+      event->selection.time = xevent->time;
+      return_val = window_private && !window_private->destroyed;
+#else
+      /* Test code, to see if SetClipboardData works when called from
+       * the window procedure.
+       */
+      {
+       HGLOBAL hdata = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE, 10);
+       char *ptr = GlobalLock (hdata);
+       strcpy (ptr, "Huhhaa");
+       GlobalUnlock (hdata);
+       if (!SetClipboardData (CF_TEXT, hdata))
+         g_print ("SetClipboardData failed: %d\n", GetLastError ());
+      }
+      *ret_valp = 0;
+      *ret_val_flagp = TRUE;
+      return_val = FALSE;
+#endif
+      break;
+#endif /* No delayed rendering */
+
+    case WM_DESTROY:
+      GDK_NOTE (EVENTS, g_print ("WM_DESTROY: %#x\n", xevent->hwnd));
+      event->any.type = GDK_DESTROY;
+      event->any.window = window;
+      if (window != NULL && window == curWnd)
+       {
+         gdk_window_unref (curWnd);
+         curWnd = NULL;
+       }
+
+      if (p_grab_window == window_private)
+       gdk_pointer_ungrab (xevent->time);
+
+      if (k_grab_window == window_private)
+       gdk_keyboard_ungrab (xevent->time);
+
+      return_val = window_private && !window_private->destroyed;
+      break;
+
+      /* Handle WINTAB events here, as we know that gdkinput.c will
+       * use the fixed WT_DEFBASE as lcMsgBase, and we thus can use the
+       * constants as case labels.
+       */
+    case WT_PACKET:
+      GDK_NOTE (EVENTS, g_print ("WT_PACKET: %d %#x\n",
+                                xevent->wParam, xevent->lParam));
+      goto wintab;
+      
+    case WT_CSRCHANGE:
+      GDK_NOTE (EVENTS, g_print ("WT_CSRCHANGE: %d %#x\n",
+                                xevent->wParam, xevent->lParam));
+      goto wintab;
+      
+    case WT_PROXIMITY:
+      GDK_NOTE (EVENTS,
+               g_print ("WT_PROXIMITY: %#x %d %d\n",
+                        xevent->wParam,
+                        LOWORD (xevent->lParam), HIWORD (xevent->lParam)));
+    wintab:
+      return_val = gdk_input_vtable.other_event(event, xevent);
+      break;
+    }
+
+bypass_switch:
+
+  if (return_val)
+    {
+      if (event->any.window)
+       gdk_window_ref (event->any.window);
+      if (((event->any.type == GDK_ENTER_NOTIFY) ||
+          (event->any.type == GDK_LEAVE_NOTIFY)) &&
+         (event->crossing.subwindow != NULL))
+       gdk_window_ref (event->crossing.subwindow);
+    }
+  else
+    {
+      /* Mark this event as having no resources to be freed */
+      event->any.window = NULL;
+      event->any.type = GDK_NOTHING;
+    }
+
+  if (window)
+    gdk_window_unref (window);
+  
+  return return_val;
+}
+
+static void
+gdk_events_queue (void)
+{
+  GList *node;
+  GdkEvent *event;
+  MSG msg;
+
+  GDK_NOTE (EVENTS, g_print ("gdk_events_queue: %s\n",
+                            (queued_events ? "yes" : "none")));
+
+  while (!gdk_event_queue_find_first()
+        && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+    {
+      GDK_NOTE (EVENTS, g_print ("gdk_events_queue: got event\n"));
+      TranslateMessage (&msg);
+
+      event = gdk_event_new ();
+      
+      event->any.type = GDK_NOTHING;
+      event->any.window = NULL;
+      event->any.send_event = FALSE;
+
+      ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
+
+      gdk_event_queue_append (event);
+      node = queued_tail;
+
+      if (gdk_event_translate (event, &msg, NULL, NULL))
+         ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
+      else
+       {
+         DefWindowProc (msg.hwnd, msg.message, msg.wParam, msg.lParam);
+         gdk_event_queue_remove_link (node);
+         g_list_free_1 (node);
+         gdk_event_free (event);
+       }
+    }
+}
+
+static gboolean  
+gdk_event_prepare (gpointer  source_data, 
+                  GTimeVal *current_time,
+                  gint     *timeout)
+{
+  MSG msg;
+  gboolean retval;
+  
+  GDK_THREADS_ENTER ();
+
+  *timeout = -1;
+
+  GDK_NOTE (EVENTS, g_print ("gdk_event_prepare\n"));
+
+  retval = (gdk_event_queue_find_first () != NULL)
+             || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
+
+  GDK_THREADS_LEAVE ();
+
+  return retval;
+}
+
+static gboolean  
+gdk_event_check (gpointer  source_data,
+                GTimeVal *current_time)
+{
+  MSG msg;
+  gboolean retval;
+  
+  GDK_NOTE (EVENTS, g_print ("gdk_event_check\n"));
+
+  GDK_THREADS_ENTER ();
+
+  if (event_poll_fd.revents & G_IO_IN)
+    retval = (gdk_event_queue_find_first () != NULL)
+             || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
+  else
+    retval = FALSE;
+
+  GDK_THREADS_LEAVE ();
+
+  return retval;
+}
+
+static GdkEvent*
+gdk_event_unqueue (void)
+{
+  GdkEvent *event = NULL;
+  GList *tmp_list;
+
+  tmp_list = gdk_event_queue_find_first ();
+
+  if (tmp_list)
+    {
+      event = tmp_list->data;
+      gdk_event_queue_remove_link (tmp_list);
+      g_list_free_1 (tmp_list);
+    }
+
+  return event;
+}
+
+static gboolean  
+gdk_event_dispatch (gpointer  source_data,
+                   GTimeVal *current_time,
+                   gpointer  user_data)
+{
+  GdkEvent *event;
+  GDK_NOTE (EVENTS, g_print ("gdk_event_dispatch\n"));
+
+  GDK_THREADS_ENTER ();
+
+  gdk_events_queue();
+  event = gdk_event_unqueue();
+
+  if (event)
+    {
+      if (event_func)
+       (*event_func) (event, event_data);
+      
+      gdk_event_free (event);
+    }
+  
+  GDK_THREADS_LEAVE ();
+
+  return TRUE;
+}
+
+static void
+gdk_synthesize_click (GdkEvent *event,
+                     gint      nclicks)
+{
+  GdkEvent temp_event;
+  
+  g_return_if_fail (event != NULL);
+  
+  temp_event = *event;
+  temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
+  
+  gdk_event_put (&temp_event);
+}
+
+/* Sends a ClientMessage to all toplevel client windows */
+gboolean
+gdk_event_send_client_message (GdkEvent *event, guint32 xid)
+{
+  /* XXX */
+  return FALSE;
+}
+
+void
+gdk_event_send_clientmessage_toall (GdkEvent *event)
+{
+  /* XXX */
+}
+
diff --git a/gdk/win32/gdkevents.c b/gdk/win32/gdkevents.c
new file mode 100644 (file)
index 0000000..02c9474
--- /dev/null
@@ -0,0 +1,2963 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-1999 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include "gdk.h"
+#include "gdkx.h"
+#include "gdkprivate.h"
+#include "gdkinput.h"
+#include "gdkkeysyms.h"
+
+#define PING() printf("%s: %d\n",__FILE__,__LINE__),fflush(stdout)
+
+typedef struct _GdkIOClosure GdkIOClosure;
+typedef struct _GdkEventPrivate GdkEventPrivate;
+
+#define DOUBLE_CLICK_TIME      250
+#define TRIPLE_CLICK_TIME      500
+#define DOUBLE_CLICK_DIST      5
+#define TRIPLE_CLICK_DIST      5
+
+typedef enum
+{
+  /* Following flag is set for events on the event queue during
+   * translation and cleared afterwards.
+   */
+  GDK_EVENT_PENDING = 1 << 0
+} GdkEventFlags;
+
+struct _GdkIOClosure
+{
+  GdkInputFunction function;
+  GdkInputCondition condition;
+  GdkDestroyNotify notify;
+  gpointer data;
+};
+
+struct _GdkEventPrivate
+{
+  GdkEvent event;
+  guint    flags;
+};
+
+/* 
+ * Private function declarations
+ */
+
+static GdkEvent *gdk_event_new         (void);
+static gint     gdk_event_apply_filters(MSG      *xevent,
+                                        GdkEvent *event,
+                                        GList    *filters);
+static gint     gdk_event_translate    (GdkEvent *event, 
+                                        MSG      *xevent,
+                                        gboolean *ret_val_flagp,
+                                        gint     *ret_valp);
+static void      gdk_events_queue       (void);
+static GdkEvent *gdk_event_unqueue      (void);
+static gboolean  gdk_event_prepare      (gpointer  source_data, 
+                                        GTimeVal *current_time,
+                                        gint     *timeout);
+static gboolean  gdk_event_check        (gpointer  source_data,
+                                        GTimeVal *current_time);
+static gboolean  gdk_event_dispatch     (gpointer  source_data,
+                                        GTimeVal *current_time,
+                                        gpointer  user_data);
+
+static void     gdk_synthesize_click   (GdkEvent     *event, 
+                                        gint          nclicks);
+
+/* Private variable declarations
+ */
+
+static guint32 button_click_time[2];       /* The last 2 button click times. Used
+                                            *  to determine if the latest button click
+                                            *  is part of a double or triple click.
+                                            */
+static GdkWindow *button_window[2];        /* The last 2 windows to receive button presses.
+                                            *  Also used to determine if the latest button
+                                            *  click is part of a double or triple click.
+                                            */
+static guint button_number[2];             /* The last 2 buttons to be pressed.
+                                            */
+static GdkWindowPrivate *p_grab_window = NULL; /* Window that currently
+                                               * holds the pointer grab
+                                               */
+
+static GdkWindowPrivate *k_grab_window = NULL; /* Window the holds the
+                                               * keyboard grab
+                                               */
+
+static GList *client_filters;  /* Filters for client messages */
+
+static gboolean p_grab_automatic;
+static GdkEventMask p_grab_event_mask;
+static gboolean p_grab_owner_events, k_grab_owner_events;
+static HCURSOR p_grab_cursor;
+
+static GdkEventFunc   event_func = NULL;    /* Callback for events */
+static gpointer       event_data = NULL;
+static GDestroyNotify event_notify = NULL;
+
+static GList *client_filters;              /* Filters for client messages */
+
+/* FIFO's for event queue, and for events put back using
+ * gdk_event_put().
+ */
+static GList *queued_events = NULL;
+static GList *queued_tail = NULL;
+
+static GSourceFuncs event_funcs = {
+  gdk_event_prepare,
+  gdk_event_check,
+  gdk_event_dispatch,
+  (GDestroyNotify)g_free
+};
+
+GPollFD event_poll_fd;
+
+static GdkWindow *curWnd = NULL;
+static HWND active = NULL;
+static gint curX, curY;
+static gdouble curXroot, curYroot;
+static UINT gdk_ping_msg;
+static gboolean ignore_WM_CHAR = FALSE;
+static gboolean is_AltGr_key = FALSE;
+
+LRESULT CALLBACK 
+gdk_WindowProc(HWND hwnd,
+              UINT message,
+              WPARAM wParam,
+              LPARAM lParam)
+{
+  GdkEvent event;
+  GdkEvent *eventp;
+  MSG msg;
+  DWORD pos;
+  gint ret_val;
+  gboolean ret_val_flag;
+
+  GDK_NOTE (EVENTS, g_print ("gdk_WindowProc: %#x\n", message));
+
+  msg.hwnd = hwnd;
+  msg.message = message;
+  msg.wParam = wParam;
+  msg.lParam = lParam;
+  msg.time = GetTickCount ();
+  pos = GetMessagePos ();
+  msg.pt.x = LOWORD (pos);
+  msg.pt.y = HIWORD (pos);
+
+  if (gdk_event_translate (&event, &msg, &ret_val_flag, &ret_val))
+    {
+#if 1
+      /* Compress configure events */
+      if (event.any.type == GDK_CONFIGURE)
+       {
+         GList *list = queued_events;
+
+         while (list != NULL
+                && (((GdkEvent *)list->data)->any.type != GDK_CONFIGURE
+                    || ((GdkEvent *)list->data)->any.window != event.any.window))
+           list = list->next;
+         if (list != NULL)
+           {
+             *((GdkEvent *)list->data) = event;
+             gdk_window_unref (event.any.window);
+             /* Wake up WaitMessage */
+             PostMessage (NULL, gdk_ping_msg, 0, 0);
+             return FALSE;
+           }
+       }
+#endif
+      eventp = gdk_event_new ();
+      *eventp = event;
+
+      gdk_event_queue_append (eventp);
+#if 1
+      /* Wake up WaitMessage */
+      PostMessage (NULL, gdk_ping_msg, 0, 0);
+#endif
+      if (ret_val_flag)
+       return ret_val;
+      else
+       return FALSE;
+    }
+
+  if (ret_val_flag)
+    return ret_val;
+  else
+    return DefWindowProc (hwnd, message, wParam, lParam);
+}
+
+/*********************************************
+ * Functions for maintaining the event queue *
+ *********************************************/
+
+/*************************************************************
+ * gdk_event_queue_find_first:
+ *     Find the first event on the queue that is not still
+ *     being filled in.
+ *   arguments:
+ *     
+ *   results:
+ *     Pointer to the list node for that event, or NULL
+ *************************************************************/
+
+static GList*
+gdk_event_queue_find_first (void)
+{
+  GList *tmp_list = queued_events;
+
+  while (tmp_list)
+    {
+      GdkEventPrivate *event = tmp_list->data;
+      if (!(event->flags & GDK_EVENT_PENDING))
+       return tmp_list;
+
+      tmp_list = g_list_next (tmp_list);
+    }
+
+  return NULL;
+}
+
+/*************************************************************
+ * gdk_event_queue_remove_link:
+ *     Remove a specified list node from the event queue.
+ *   arguments:
+ *     node: Node to remove.
+ *   results:
+ *************************************************************/
+
+static void
+gdk_event_queue_remove_link (GList *node)
+{
+  if (node->prev)
+    node->prev->next = node->next;
+  else
+    queued_events = node->next;
+  
+  if (node->next)
+    node->next->prev = node->prev;
+  else
+    queued_tail = node->prev;
+  
+}
+
+/*************************************************************
+ * gdk_event_queue_append:
+ *     Append an event onto the tail of the event queue.
+ *   arguments:
+ *     event: Event to append.
+ *   results:
+ *************************************************************/
+
+void
+gdk_event_queue_append (GdkEvent *event)
+{
+  queued_tail = g_list_append (queued_tail, event);
+  
+  if (!queued_events)
+    queued_events = queued_tail;
+  else
+    queued_tail = queued_tail->next;
+}
+
+void 
+gdk_events_init (void)
+{
+  if (g_pipe_readable_msg == 0)
+    g_pipe_readable_msg = RegisterWindowMessage ("g-pipe-readable");
+
+  g_source_add (GDK_PRIORITY_EVENTS, TRUE, &event_funcs, NULL, NULL, NULL);
+
+  event_poll_fd.fd = G_WIN32_MSG_HANDLE;
+  event_poll_fd.events = G_IO_IN;
+  
+  g_main_add_poll (&event_poll_fd, GDK_PRIORITY_EVENTS);
+
+  button_click_time[0] = 0;
+  button_click_time[1] = 0;
+  button_window[0] = NULL;
+  button_window[1] = NULL;
+  button_number[0] = -1;
+  button_number[1] = -1;
+
+  gdk_ping_msg = RegisterWindowMessage ("gdk-ping");
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_events_pending
+ *
+ *   Returns if events are pending on the queue.
+ *
+ * Arguments:
+ *
+ * Results:
+ *   Returns TRUE if events are pending
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gboolean
+gdk_events_pending (void)
+{
+  MSG msg;
+
+  return (gdk_event_queue_find_first() || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE));
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_get_graphics_expose
+ *
+ *   Waits for a GraphicsExpose or NoExpose event
+ *
+ * Arguments:
+ *
+ * Results: 
+ *   For GraphicsExpose events, returns a pointer to the event
+ *   converted into a GdkEvent Otherwise, returns NULL.
+ *
+ * Side effects:
+ *
+ *-------------------------------------------------------------- */
+
+GdkEvent*
+gdk_event_get_graphics_expose (GdkWindow *window)
+{
+  MSG xevent;
+  GdkEvent *event;
+  GdkWindowPrivate *private = (GdkWindowPrivate *) window;
+
+  g_return_val_if_fail (window != NULL, NULL);
+  
+  GDK_NOTE (EVENTS, g_print ("gdk_event_get_graphics_expose\n"));
+
+#if 1
+  /* Some nasty bugs here, just return NULL for now. */
+  return NULL;
+#else
+  if (GetMessage (&xevent, private->xwindow, WM_PAINT, WM_PAINT))
+    {
+      event = gdk_event_new ();
+      
+      if (gdk_event_translate (event, &xevent, NULL, NULL))
+       return event;
+      else
+       gdk_event_free (event);
+    }
+  
+  return NULL; 
+#endif
+}
+
+/************************
+ * Exposure compression *
+ ************************/
+
+/* I don't bother with exposure compression on Win32. Windows compresses
+ * WM_PAINT events by itself.
+ */
+
+/*************************************************************
+ * gdk_event_handler_set:
+ *     
+ *   arguments:
+ *     func: Callback function to be called for each event.
+ *     data: Data supplied to the function
+ *     notify: function called when function is no longer needed
+ * 
+ *   results:
+ *************************************************************/
+
+void 
+gdk_event_handler_set (GdkEventFunc   func,
+                      gpointer       data,
+                      GDestroyNotify notify)
+{
+  if (event_notify)
+    (*event_notify) (event_data);
+
+  event_func = func;
+  event_data = data;
+  event_notify = notify;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_get
+ *
+ *   Gets the next event.
+ *
+ * Arguments:
+ *
+ * Results:
+ *   If an event is waiting that we care about, returns 
+ *   a pointer to that event, to be freed with gdk_event_free.
+ *   Otherwise, returns NULL.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+GdkEvent*
+gdk_event_get (void)
+{
+  gdk_events_queue();
+
+  return gdk_event_unqueue();
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_peek
+ *
+ *   Gets the next event.
+ *
+ * Arguments:
+ *
+ * Results:
+ *   If an event is waiting that we care about, returns 
+ *   a copy of that event, but does not remove it from
+ *   the queue. The pointer is to be freed with gdk_event_free.
+ *   Otherwise, returns NULL.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+GdkEvent*
+gdk_event_peek (void)
+{
+  GList *tmp_list;
+
+  tmp_list = gdk_event_queue_find_first ();
+  
+  if (tmp_list)
+    return gdk_event_copy (tmp_list->data);
+  else
+    return NULL;
+}
+
+void
+gdk_event_put (GdkEvent *event)
+{
+  GdkEvent *new_event;
+  GList *tmp_list;
+  
+  g_return_if_fail (event != NULL);
+  
+  new_event = gdk_event_copy (event);
+
+  gdk_event_queue_append (new_event);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_copy
+ *
+ *   Copy a event structure into new storage.
+ *
+ * Arguments:
+ *   "event" is the event struct to copy.
+ *
+ * Results:
+ *   A new event structure.  Free it with gdk_event_free.
+ *
+ * Side effects:
+ *   The reference count of the window in the event is increased.
+ *
+ *--------------------------------------------------------------
+ */
+
+static GMemChunk *event_chunk = NULL;
+
+static GdkEvent*
+gdk_event_new (void)
+{
+  GdkEventPrivate *new_event;
+  
+  if (event_chunk == NULL)
+    event_chunk = g_mem_chunk_new ("events",
+                                  sizeof (GdkEventPrivate),
+                                  4096,
+                                  G_ALLOC_AND_FREE);
+  
+  new_event = g_chunk_new (GdkEventPrivate, event_chunk);
+  new_event->flags = 0;
+  
+  return (GdkEvent *) new_event;
+}
+
+GdkEvent*
+gdk_event_copy (GdkEvent *event)
+{
+  GdkEvent *new_event;
+  
+  g_return_val_if_fail (event != NULL, NULL);
+  
+  new_event = gdk_event_new ();
+  
+  *new_event = *event;
+  gdk_window_ref (new_event->any.window);
+  
+  switch (event->any.type)
+    {
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+      new_event->key.string = g_strdup (event->key.string);
+      break;
+      
+    case GDK_ENTER_NOTIFY:
+    case GDK_LEAVE_NOTIFY:
+      if (event->crossing.subwindow != NULL)
+       gdk_window_ref (event->crossing.subwindow);
+      break;
+      
+    case GDK_DRAG_ENTER:
+    case GDK_DRAG_LEAVE:
+    case GDK_DRAG_MOTION:
+    case GDK_DRAG_STATUS:
+    case GDK_DROP_START:
+    case GDK_DROP_FINISHED:
+      gdk_drag_context_ref (event->dnd.context);
+      break;
+      
+    default:
+      break;
+    }
+  
+  return new_event;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_free
+ *
+ *   Free a event structure obtained from gdk_event_copy.  Do not use
+ *   with other event structures.
+ *
+ * Arguments:
+ *   "event" is the event struct to free.
+ *
+ * Results:
+ *
+ * Side effects:
+ *   The reference count of the window in the event is decreased and
+ *   might be freed, too.
+ *
+ *-------------------------------------------------------------- */
+
+void
+gdk_event_free (GdkEvent *event)
+{
+  g_return_if_fail (event != NULL);
+
+  g_assert (event_chunk != NULL); /* paranoid */
+  
+  if (event->any.window)
+    gdk_window_unref (event->any.window);
+  
+  switch (event->any.type)
+    {
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+      g_free (event->key.string);
+      break;
+      
+    case GDK_ENTER_NOTIFY:
+    case GDK_LEAVE_NOTIFY:
+      if (event->crossing.subwindow != NULL)
+       gdk_window_unref (event->crossing.subwindow);
+      break;
+      
+    case GDK_DRAG_ENTER:
+    case GDK_DRAG_LEAVE:
+    case GDK_DRAG_MOTION:
+    case GDK_DRAG_STATUS:
+    case GDK_DROP_START:
+    case GDK_DROP_FINISHED:
+      gdk_drag_context_unref (event->dnd.context);
+      break;
+      
+    default:
+      break;
+    }
+  
+  g_mem_chunk_free (event_chunk, event);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_event_get_time:
+ *    Get the timestamp from an event.
+ *   arguments:
+ *     event:
+ *   results:
+ *    The event's time stamp, if it has one, otherwise
+ *    GDK_CURRENT_TIME.
+ *--------------------------------------------------------------
+ */
+
+guint32
+gdk_event_get_time (GdkEvent *event)
+{
+  if (event)
+    switch (event->type)
+      {
+      case GDK_MOTION_NOTIFY:
+       return event->motion.time;
+      case GDK_BUTTON_PRESS:
+      case GDK_2BUTTON_PRESS:
+      case GDK_3BUTTON_PRESS:
+      case GDK_BUTTON_RELEASE:
+       return event->button.time;
+      case GDK_KEY_PRESS:
+      case GDK_KEY_RELEASE:
+       return event->key.time;
+      case GDK_ENTER_NOTIFY:
+      case GDK_LEAVE_NOTIFY:
+       return event->crossing.time;
+      case GDK_PROPERTY_NOTIFY:
+       return event->property.time;
+      case GDK_SELECTION_CLEAR:
+      case GDK_SELECTION_REQUEST:
+      case GDK_SELECTION_NOTIFY:
+       return event->selection.time;
+      case GDK_PROXIMITY_IN:
+      case GDK_PROXIMITY_OUT:
+       return event->proximity.time;
+      case GDK_DRAG_ENTER:
+      case GDK_DRAG_LEAVE:
+      case GDK_DRAG_MOTION:
+      case GDK_DRAG_STATUS:
+      case GDK_DROP_START:
+      case GDK_DROP_FINISHED:
+       return event->dnd.time;
+      default:                 /* use current time */
+       break;
+      }
+  
+  return GDK_CURRENT_TIME;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_set_show_events
+ *
+ *   Turns on/off the showing of events.
+ *
+ * Arguments:
+ *   "show_events" is a boolean describing whether or
+ *   not to show the events gdk receives.
+ *
+ * Results:
+ *
+ * Side effects:
+ *   When "show_events" is TRUE, calls to "gdk_event_get"
+ *   will output debugging informatin regarding the event
+ *   received to stdout.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_set_show_events (gint show_events)
+{
+  if (show_events)
+    gdk_debug_flags |= GDK_DEBUG_EVENTS;
+  else
+    gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
+}
+
+gint
+gdk_get_show_events (void)
+{
+  return gdk_debug_flags & GDK_DEBUG_EVENTS;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_pointer_grab
+ *
+ *   Grabs the pointer to a specific window
+ *
+ * Arguments:
+ *   "window" is the window which will receive the grab
+ *   "owner_events" specifies whether events will be reported as is,
+ *     or relative to "window"
+ *   "event_mask" masks only interesting events
+ *   "confine_to" limits the cursor movement to the specified window
+ *   "cursor" changes the cursor for the duration of the grab
+ *   "time" specifies the time
+ *
+ * Results:
+ *
+ * Side effects:
+ *   requires a corresponding call to gdk_pointer_ungrab
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_pointer_grab (GdkWindow *    window,
+                 gint            owner_events,
+                 GdkEventMask    event_mask,
+                 GdkWindow *     confine_to,
+                 GdkCursor *     cursor,
+                 guint32         time)
+{
+  GdkWindowPrivate *window_private;
+  HWND xwindow;
+  HWND xconfine_to;
+  HCURSOR xcursor;
+  GdkWindowPrivate *confine_to_private;
+  GdkCursorPrivate *cursor_private;
+  gint return_val;
+
+  g_return_val_if_fail (window != NULL, 0);
+  
+  window_private = (GdkWindowPrivate*) window;
+  confine_to_private = (GdkWindowPrivate*) confine_to;
+  cursor_private = (GdkCursorPrivate*) cursor;
+  
+  xwindow = window_private->xwindow;
+  
+  if (!confine_to || confine_to_private->destroyed)
+    xconfine_to = NULL;
+  else
+    xconfine_to = confine_to_private->xwindow;
+  
+  if (!cursor)
+    xcursor = NULL;
+  else
+    xcursor = cursor_private->xcursor;
+  
+  if (gdk_input_vtable.grab_pointer)
+    return_val = gdk_input_vtable.grab_pointer (window,
+                                               owner_events,
+                                               event_mask,
+                                               confine_to,
+                                               time);
+  else
+    return_val = Success;
+  
+  if (return_val == Success)
+    {
+      if (!window_private->destroyed)
+      {
+       GDK_NOTE (EVENTS, g_print ("gdk_pointer_grab: %#x %s %#x\n",
+                                  xwindow,
+                                  (owner_events ? "TRUE" : "FALSE"),
+                                  xcursor));
+       p_grab_event_mask = event_mask;
+       p_grab_owner_events = owner_events != 0;
+       p_grab_automatic = FALSE;
+
+#if 0 /* Menus don't work if we use mouse capture. Pity, because many other
+       * things work better with mouse capture.
+       */
+       SetCapture (xwindow);
+#endif
+       return_val = GrabSuccess;
+      }
+      else
+       return_val = AlreadyGrabbed;
+    }
+  
+  if (return_val == GrabSuccess)
+    {
+      p_grab_window = window_private;
+      p_grab_cursor = xcursor;
+    }
+  
+  return return_val;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_pointer_ungrab
+ *
+ *   Releases any pointer grab
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_pointer_ungrab (guint32 time)
+{
+  if (gdk_input_vtable.ungrab_pointer)
+    gdk_input_vtable.ungrab_pointer (time);
+#if 0
+  if (GetCapture () != NULL)
+    ReleaseCapture ();
+#endif
+  GDK_NOTE (EVENTS, g_print ("gdk_pointer_ungrab\n"));
+
+  p_grab_window = NULL;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_pointer_is_grabbed
+ *
+ *   Tell wether there is an active x pointer grab in effect
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_pointer_is_grabbed (void)
+{
+  return p_grab_window != NULL;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_keyboard_grab
+ *
+ *   Grabs the keyboard to a specific window
+ *
+ * Arguments:
+ *   "window" is the window which will receive the grab
+ *   "owner_events" specifies whether events will be reported as is,
+ *     or relative to "window"
+ *   "time" specifies the time
+ *
+ * Results:
+ *
+ * Side effects:
+ *   requires a corresponding call to gdk_keyboard_ungrab
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_keyboard_grab (GdkWindow *    window,
+                  gint            owner_events,
+                  guint32         time)
+{
+  GdkWindowPrivate *window_private;
+  gint return_val;
+  
+  g_return_val_if_fail (window != NULL, 0);
+  
+  window_private = (GdkWindowPrivate*) window;
+  
+  GDK_NOTE (EVENTS, g_print ("gdk_keyboard_grab %#x\n",
+                            window_private->xwindow));
+
+  if (!window_private->destroyed)
+    {
+      k_grab_owner_events = owner_events != 0;
+      return_val = GrabSuccess;
+    }
+  else
+    return_val = AlreadyGrabbed;
+
+  if (return_val == GrabSuccess)
+    k_grab_window = window_private;
+  
+  return return_val;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_keyboard_ungrab
+ *
+ *   Releases any keyboard grab
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_keyboard_ungrab (guint32 time)
+{
+  GDK_NOTE (EVENTS, g_print ("gdk_keyboard_ungrab\n"));
+
+  k_grab_window = NULL;
+}
+
+static void
+gdk_io_destroy (gpointer data)
+{
+  GdkIOClosure *closure = data;
+
+  if (closure->notify)
+    closure->notify (closure->data);
+
+  g_free (closure);
+}
+
+static gboolean  
+gdk_io_invoke (GIOChannel   *source,
+              GIOCondition  condition,
+              gpointer      data)
+{
+  GdkIOClosure *closure = data;
+  GdkInputCondition gdk_cond = 0;
+
+  if (condition & (G_IO_IN | G_IO_PRI))
+    gdk_cond |= GDK_INPUT_READ;
+  if (condition & G_IO_OUT)
+    gdk_cond |= GDK_INPUT_WRITE;
+  if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+    gdk_cond |= GDK_INPUT_EXCEPTION;
+
+  if (closure->condition & gdk_cond)
+    closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);
+
+  return TRUE;
+}
+
+gint
+gdk_input_add_full (gint             source,
+                   GdkInputCondition condition,
+                   GdkInputFunction  function,
+                   gpointer          data,
+                   GdkDestroyNotify  destroy)
+{
+  guint result;
+  GdkIOClosure *closure = g_new (GdkIOClosure, 1);
+  GIOChannel *channel;
+  GIOCondition cond = 0;
+
+  closure->function = function;
+  closure->condition = condition;
+  closure->notify = destroy;
+  closure->data = data;
+
+  if (condition & GDK_INPUT_READ)
+    cond |= (G_IO_IN | G_IO_PRI);
+  if (condition & GDK_INPUT_WRITE)
+    cond |= G_IO_OUT;
+  if (condition & GDK_INPUT_EXCEPTION)
+    cond |= G_IO_ERR|G_IO_HUP|G_IO_NVAL;
+
+  channel = g_io_channel_unix_new (source);
+  result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond,
+                               gdk_io_invoke,
+                               closure, gdk_io_destroy);
+  g_io_channel_unref (channel);
+
+  return result;
+}
+
+gint
+gdk_input_add (gint             source,
+              GdkInputCondition condition,
+              GdkInputFunction  function,
+              gpointer          data)
+{
+  return gdk_input_add_full (source, condition, function, data, NULL);
+}
+
+void
+gdk_input_remove (gint tag)
+{
+  g_source_remove (tag);
+}
+
+static gint
+gdk_event_apply_filters (MSG      *xevent,
+                        GdkEvent *event,
+                        GList    *filters)
+{
+  GdkEventFilter *filter;
+  GList *tmp_list;
+  GdkFilterReturn result;
+  
+  tmp_list = filters;
+  
+  while (tmp_list)
+    {
+      filter = (GdkEventFilter *) tmp_list->data;
+      
+      result = (*filter->function) (xevent, event, filter->data);
+      if (result !=  GDK_FILTER_CONTINUE)
+       return result;
+      
+      tmp_list = tmp_list->next;
+    }
+  
+  return GDK_FILTER_CONTINUE;
+}
+
+void 
+gdk_add_client_message_filter (GdkAtom       message_type,
+                              GdkFilterFunc func,
+                              gpointer      data)
+{
+  GdkClientFilter *filter = g_new (GdkClientFilter, 1);
+
+  filter->type = message_type;
+  filter->function = func;
+  filter->data = data;
+  
+  client_filters = g_list_prepend (client_filters, filter);
+}
+
+static void
+synthesize_crossing_events (GdkWindow *window,
+                           MSG       *xevent)
+{
+  GdkEvent *event;
+  GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
+  GdkWindowPrivate *curWnd_private = (GdkWindowPrivate *) curWnd;
+  
+  if (curWnd && (curWnd_private->event_mask & GDK_LEAVE_NOTIFY_MASK))
+    {
+      GDK_NOTE (EVENTS, g_print ("synthesizing LEAVE_NOTIFY event\n"));
+
+      event = gdk_event_new ();
+      event->crossing.type = GDK_LEAVE_NOTIFY;
+      event->crossing.window = curWnd;
+      gdk_window_ref (event->crossing.window);
+      event->crossing.subwindow = NULL;
+      event->crossing.time = xevent->time;
+      event->crossing.x = curX;
+      event->crossing.y = curY;
+      event->crossing.x_root = curXroot;
+      event->crossing.y_root = curYroot;
+      event->crossing.mode = GDK_CROSSING_NORMAL;
+      event->crossing.detail = GDK_NOTIFY_UNKNOWN;
+
+      event->crossing.focus = TRUE; /* ??? */
+      event->crossing.state = 0; /* ??? */
+
+      gdk_event_queue_append (event);
+    }
+
+  if (window_private && (window_private->event_mask & GDK_ENTER_NOTIFY_MASK))
+    {
+      GDK_NOTE (EVENTS, g_print ("synthesizing ENTER_NOTIFY event\n"));
+      
+      event = gdk_event_new ();
+      event->crossing.type = GDK_ENTER_NOTIFY;
+      event->crossing.window = window;
+      gdk_window_ref (event->crossing.window);
+      event->crossing.subwindow = NULL;
+      event->crossing.time = xevent->time;
+      event->crossing.x = LOWORD (xevent->lParam);
+      event->crossing.y = HIWORD (xevent->lParam);
+      event->crossing.x_root = (gfloat) xevent->pt.x;
+      event->crossing.y_root = (gfloat) xevent->pt.y;
+      event->crossing.mode = GDK_CROSSING_NORMAL;
+      event->crossing.detail = GDK_NOTIFY_UNKNOWN;
+      
+      event->crossing.focus = TRUE; /* ??? */
+      event->crossing.state = 0; /* ??? */
+      
+      gdk_event_queue_append (event);
+
+      if (window_private->extension_events != 0
+         && gdk_input_vtable.enter_event)
+       gdk_input_vtable.enter_event (&event->crossing, window);
+    }
+  
+  if (curWnd)
+    gdk_window_unref (curWnd);
+  curWnd = window;
+  gdk_window_ref (curWnd);
+}
+
+static gint
+gdk_event_translate (GdkEvent *event,
+                    MSG      *xevent,
+                    gboolean *ret_val_flagp,
+                    gint     *ret_valp)
+{
+  GdkWindow *window;
+  GdkWindowPrivate *window_private;
+
+  GdkColormapPrivate *colormap_private;
+  HWND owner;
+  DWORD dwStyle;
+  PAINTSTRUCT paintstruct;
+  HDC hdc;
+  HBRUSH hbr;
+  RECT rect;
+  POINT pt;
+  GdkWindowPrivate *curWnd_private;
+  GdkEventMask mask;
+  int button;
+  int i, j;
+  gchar buf[256];
+  gint charcount;
+  gint return_val;
+  gboolean flag;
+  
+  return_val = FALSE;
+  
+  if (ret_val_flagp)
+    *ret_val_flagp = FALSE;
+
+  if (xevent->message == gdk_ping_msg)
+    {
+      /* Messages we post ourselves just to wakeup WaitMessage.  */
+      return FALSE;
+    }
+
+  window = gdk_window_lookup (xevent->hwnd);
+  window_private = (GdkWindowPrivate *) window;
+  
+  if (xevent->message == g_pipe_readable_msg)
+    {
+      GDK_NOTE (EVENTS, g_print ("g_pipe_readable_msg: %d %d\n",
+                                xevent->wParam, xevent->lParam));
+
+      g_io_channel_win32_pipe_readable (xevent->wParam, xevent->lParam);
+      return FALSE;
+    }
+
+  if (window != NULL)
+    gdk_window_ref (window);
+  else
+    {
+      /* Handle WM_QUIT here ? */
+      if (xevent->message == WM_QUIT)
+       {
+         GDK_NOTE (EVENTS, g_print ("WM_QUIT: %d\n", xevent->wParam));
+         exit (xevent->wParam);
+       }
+      else if (xevent->message == WM_MOVE
+              || xevent->message == WM_SIZE)
+       {
+         /* It's quite normal to get these messages before we have
+          * had time to register the window in our lookup table, or
+          * when the window is being destroyed and we already have
+          * removed it. Repost the same message to our queue so that
+          * we will get it later when we are prepared.
+          */
+         PostMessage (xevent->hwnd, xevent->message,
+                      xevent->wParam, xevent->lParam);
+       }
+      else if (xevent->message == WM_NCCREATE
+              || xevent->message == WM_CREATE
+              || xevent->message == WM_GETMINMAXINFO
+              || xevent->message == WM_NCCALCSIZE
+              || xevent->message == WM_NCDESTROY
+              || xevent->message == WM_DESTROY)
+       {
+         /* Nothing */
+       }
+      return FALSE;
+    }
+  
+  event->any.window = window;
+
+  if (window_private && window_private->destroyed)
+    {
+    }
+  else
+    {
+      /* Check for filters for this window */
+      GdkFilterReturn result;
+      result = gdk_event_apply_filters (xevent, event,
+                                       window_private
+                                       ?window_private->filters
+                                       :gdk_default_filters);
+      
+      if (result != GDK_FILTER_CONTINUE)
+       {
+         return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
+       }
+    }
+
+  if (xevent->message == gdk_selection_notify_msg)
+    {
+      GDK_NOTE (SELECTION, g_print ("gdk_selection_notify_msg: %#x\n",
+                                   xevent->hwnd));
+
+      event->selection.type = GDK_SELECTION_NOTIFY;
+      event->selection.window = window;
+      event->selection.selection = xevent->wParam;
+      event->selection.target = xevent->lParam;
+      event->selection.property = gdk_selection_property;
+      event->selection.time = xevent->time;
+
+      return_val = window_private && !window_private->destroyed;
+
+      /* Will pass through switch below without match */
+    }
+  else if (xevent->message == gdk_selection_request_msg)
+    {
+      GDK_NOTE (SELECTION, g_print ("gdk_selection_request_msg: %#x\n",
+                                   xevent->hwnd));
+
+      event->selection.type = GDK_SELECTION_REQUEST;
+      event->selection.window = window;
+      event->selection.selection = gdk_clipboard_atom;
+      event->selection.target = GDK_TARGET_STRING;
+      event->selection.property = gdk_selection_property;
+      event->selection.requestor = (guint32) xevent->hwnd;
+      event->selection.time = xevent->time;
+
+      return_val = window_private && !window_private->destroyed;
+
+      /* Again, will pass through switch below without match */
+    }
+  else if (xevent->message == gdk_selection_clear_msg)
+    {
+      GDK_NOTE (SELECTION, g_print ("gdk_selection_clear_msg: %#x\n",
+                                   xevent->hwnd));
+
+      event->selection.type = GDK_SELECTION_CLEAR;
+      event->selection.window = window;
+      event->selection.selection = xevent->wParam;
+      event->selection.time = xevent->time;
+
+      return_val = window_private && !window_private->destroyed;
+
+      /* Once again, we will pass through switch below without match */
+    }
+  else
+    {
+      GList *tmp_list;
+      GdkFilterReturn result = GDK_FILTER_CONTINUE;
+
+      tmp_list = client_filters;
+      while (tmp_list)
+       {
+         GdkClientFilter *filter = tmp_list->data;
+         if (filter->type == xevent->message)
+           {
+             GDK_NOTE (EVENTS, g_print ("client filter matched\n"));
+             result = (*filter->function) (xevent, event, filter->data);
+             switch (result)
+               {
+               case GDK_FILTER_REMOVE:
+                 return_val = FALSE;
+                 break;
+
+               case GDK_FILTER_TRANSLATE:
+                 return_val = TRUE;
+                 break;
+
+               case GDK_FILTER_CONTINUE:
+                 return_val = TRUE;
+                 event->client.type = GDK_CLIENT_EVENT;
+                 event->client.window = window;
+                 event->client.message_type = xevent->message;
+                 event->client.data_format = 0;
+                 event->client.data.l[0] = xevent->wParam;
+                 event->client.data.l[1] = xevent->lParam;
+                 break;
+               }
+             goto bypass_switch; /* Ouch */
+           }
+         tmp_list = tmp_list->next;
+       }
+    }
+
+  switch (xevent->message)
+    {
+    case WM_SYSKEYUP:
+    case WM_SYSKEYDOWN:
+      GDK_NOTE (EVENTS,
+               g_print ("WM_SYSKEY%s: %#x  key: %s  %#x %#.08x\n",
+                        (xevent->message == WM_SYSKEYUP ? "UP" : "DOWN"),
+                        xevent->hwnd,
+                        (GetKeyNameText (xevent->lParam, buf,
+                                         sizeof (buf)) > 0 ?
+                         buf : ""),
+                        xevent->wParam,
+                        xevent->lParam));
+
+      /* Let the system handle Alt-Tab and Alt-Enter */
+      if (xevent->wParam == VK_TAB
+         || xevent->wParam == VK_RETURN
+         || xevent->wParam == VK_F4)
+       break;
+      /* If posted without us having keyboard focus, ignore */
+      if (!(xevent->lParam & 0x20000000))
+       break;
+#if 0
+      /* don't generate events for just the Alt key */
+      if (xevent->wParam == VK_MENU)
+       break;
+#endif
+      /* Jump to code in common with WM_KEYUP and WM_KEYDOWN */
+      goto keyup_or_down;
+
+    case WM_KEYUP:
+    case WM_KEYDOWN:
+      GDK_NOTE (EVENTS, 
+               g_print ("WM_KEY%s: %#x  key: %s  %#x %#.08x\n",
+                        (xevent->message == WM_KEYUP ? "UP" : "DOWN"),
+                        xevent->hwnd,
+                        (GetKeyNameText (xevent->lParam, buf,
+                                         sizeof (buf)) > 0 ?
+                         buf : ""),
+                        xevent->wParam,
+                        xevent->lParam));
+
+      ignore_WM_CHAR = TRUE;
+    keyup_or_down:
+      if (k_grab_window != NULL
+         && !k_grab_owner_events)
+       {
+         /* Keyboard is grabbed with owner_events FALSE */
+         GDK_NOTE (EVENTS,
+                   g_print ("grabbed, owner_events FALSE, "
+                            "sending to %#x\n", k_grab_window->xwindow));
+         event->key.window = (GdkWindow *) k_grab_window;
+       }
+      else if (window_private
+              && (((xevent->message == WM_KEYUP
+                    || xevent->message == WM_SYSKEYUP)
+                   && !(window_private->event_mask & GDK_KEY_RELEASE_MASK))
+                  || ((xevent->message == WM_KEYDOWN
+                       || xevent->message == WM_SYSKEYDOWN)
+                      && !(window_private->event_mask & GDK_KEY_PRESS_MASK))))
+       {
+         /* Owner window doesn't want it */
+         if (k_grab_window != NULL
+             && k_grab_owner_events)
+           {
+             /* Keyboard is grabbed with owner_events TRUE */
+             GDK_NOTE (EVENTS,
+                       g_print ("grabbed, owner_events TRUE, doesn't want it, "
+                                "sending to %#x\n", k_grab_window->xwindow));
+             event->key.window = (GdkWindow *) k_grab_window;
+           }
+         else
+           {
+             /* Owner doesn't want it, neither is it grabbed, so
+              * propagate to parent.
+              */
+             if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+               break;
+             gdk_window_unref (window);
+             window = window_private->parent;
+             gdk_window_ref (window);
+             window_private = (GdkWindowPrivate *) window;
+             GDK_NOTE (EVENTS,
+                       g_print ("not wanted, not grabbed, "
+                                "sending to %#x\n", window_private->xwindow));
+             goto keyup_or_down;
+           }
+       }
+             
+      switch (xevent->wParam)
+       {
+       case VK_LBUTTON:
+         event->key.keyval = GDK_Pointer_Button1; break;
+       case VK_RBUTTON:
+         event->key.keyval = GDK_Pointer_Button3; break;
+       case VK_MBUTTON:
+         event->key.keyval = GDK_Pointer_Button2; break;
+       case VK_CANCEL:
+         event->key.keyval = GDK_Cancel; break;
+       case VK_BACK:
+         event->key.keyval = GDK_BackSpace; break;
+       case VK_TAB:
+         event->key.keyval = GDK_Tab; break;
+       case VK_CLEAR:
+         event->key.keyval = GDK_Clear; break;
+       case VK_RETURN:
+         event->key.keyval = GDK_Return; break;
+       case VK_SHIFT:
+         event->key.keyval = GDK_Shift_L; break;
+       case VK_CONTROL:
+         if (xevent->lParam & 0x01000000)
+           event->key.keyval = GDK_Control_R;
+         else
+           event->key.keyval = GDK_Control_L;
+         break;
+       case VK_MENU:
+         if (xevent->lParam & 0x01000000)
+           {
+             /* AltGr key comes in as Control+Right Alt */
+             if (GetKeyState (VK_CONTROL) < 0)
+               {
+                 ignore_WM_CHAR = FALSE;
+                 is_AltGr_key = TRUE;
+               }
+             event->key.keyval = GDK_Alt_R;
+           }
+         else
+           event->key.keyval = GDK_Alt_L;
+         break;
+       case VK_PAUSE:
+         event->key.keyval = GDK_Pause; break;
+       case VK_CAPITAL:
+         event->key.keyval = GDK_Caps_Lock; break;
+       case VK_ESCAPE:
+         event->key.keyval = GDK_Escape; break;
+       case VK_PRIOR:
+         event->key.keyval = GDK_Prior; break;
+       case VK_NEXT:
+         event->key.keyval = GDK_Next; break;
+       case VK_END:
+         event->key.keyval = GDK_End; break;
+       case VK_HOME:
+         event->key.keyval = GDK_Home; break;
+       case VK_LEFT:
+         event->key.keyval = GDK_Left; break;
+       case VK_UP:
+         event->key.keyval = GDK_Up; break;
+       case VK_RIGHT:
+         event->key.keyval = GDK_Right; break;
+       case VK_DOWN:
+         event->key.keyval = GDK_Down; break;
+       case VK_SELECT:
+         event->key.keyval = GDK_Select; break;
+       case VK_PRINT:
+         event->key.keyval = GDK_Print; break;
+       case VK_EXECUTE:
+         event->key.keyval = GDK_Execute; break;
+       case VK_INSERT:
+         event->key.keyval = GDK_Insert; break;
+       case VK_DELETE:
+         event->key.keyval = GDK_Delete; break;
+       case VK_HELP:
+         event->key.keyval = GDK_Help; break;
+       case VK_NUMPAD0:
+       case VK_NUMPAD1:
+       case VK_NUMPAD2:
+       case VK_NUMPAD3:
+       case VK_NUMPAD4:
+       case VK_NUMPAD5:
+       case VK_NUMPAD6:
+       case VK_NUMPAD7:
+       case VK_NUMPAD8:
+       case VK_NUMPAD9:
+         /* Apparently applications work better if we just pass numpad digits
+          * on as real digits? So wait for the WM_CHAR instead.
+          */
+         ignore_WM_CHAR = FALSE;
+         break;
+       case VK_MULTIPLY:
+         event->key.keyval = GDK_KP_Multiply; break;
+       case VK_ADD:
+         event->key.keyval = GDK_KP_Add; break;
+       case VK_SEPARATOR:
+         event->key.keyval = GDK_KP_Separator; break;
+       case VK_SUBTRACT:
+         event->key.keyval = GDK_KP_Subtract; break;
+       case VK_DECIMAL:
+#if 0
+         event->key.keyval = GDK_KP_Decimal; break;
+#else
+         /* The keypad decimal key should also be passed on as the decimal
+          * sign ('.' or ',' depending on the Windows locale settings,
+          * apparently). So wait for the WM_CHAR here, also.
+          */
+         ignore_WM_CHAR = FALSE;
+         break;
+#endif
+       case VK_DIVIDE:
+         event->key.keyval = GDK_KP_Divide; break;
+       case VK_F1:
+         event->key.keyval = GDK_F1; break;
+       case VK_F2:
+         event->key.keyval = GDK_F2; break;
+       case VK_F3:
+         event->key.keyval = GDK_F3; break;
+       case VK_F4:
+         event->key.keyval = GDK_F4; break;
+       case VK_F5:
+         event->key.keyval = GDK_F5; break;
+       case VK_F6:
+         event->key.keyval = GDK_F6; break;
+       case VK_F7:
+         event->key.keyval = GDK_F7; break;
+       case VK_F8:
+         event->key.keyval = GDK_F8; break;
+       case VK_F9:
+         event->key.keyval = GDK_F9; break;
+       case VK_F10:
+         event->key.keyval = GDK_F10; break;
+       case VK_F11:
+         event->key.keyval = GDK_F11; break;
+       case VK_F12:
+         event->key.keyval = GDK_F12; break;
+       case VK_F13:
+         event->key.keyval = GDK_F13; break;
+       case VK_F14:
+         event->key.keyval = GDK_F14; break;
+       case VK_F15:
+         event->key.keyval = GDK_F15; break;
+       case VK_F16:
+         event->key.keyval = GDK_F16; break;
+       default:
+         if (xevent->message == WM_SYSKEYDOWN || xevent->message == WM_SYSKEYUP)
+           {
+             event->key.keyval = xevent->wParam;
+           }
+         else
+           {
+             ignore_WM_CHAR = FALSE;
+             event->key.keyval = GDK_VoidSymbol;
+           }
+         break;
+       }
+
+      if (!ignore_WM_CHAR)
+       break;
+
+      is_AltGr_key = FALSE;
+      event->key.type = ((xevent->message == WM_KEYDOWN
+                         | xevent->message == WM_SYSKEYDOWN) ?
+                        GDK_KEY_PRESS : GDK_KEY_RELEASE);
+      event->key.window = window;
+      event->key.time = xevent->time;
+      event->key.state = 0;
+      if (GetKeyState (VK_SHIFT) < 0)
+       event->key.state |= GDK_SHIFT_MASK;
+      if (GetKeyState (VK_CAPITAL) & 0x1)
+       event->key.state |= GDK_LOCK_MASK;
+      if (GetKeyState (VK_CONTROL) < 0)
+       event->key.state |= GDK_CONTROL_MASK;
+      if (xevent->wParam != VK_MENU && GetKeyState (VK_MENU) < 0)
+       event->key.state |= GDK_MOD1_MASK;
+      event->key.length = 0;
+      return_val = window_private && !window_private->destroyed;
+      event->key.string = NULL;
+      break;
+
+    case WM_CHAR:
+      GDK_NOTE (EVENTS, 
+               g_print ("WM_CHAR: %#x  char: %#x %#.08x  %s\n",
+                        xevent->hwnd,
+                        xevent->wParam,
+                        xevent->lParam,
+                        (ignore_WM_CHAR ? "ignored" : "")));
+
+      if (ignore_WM_CHAR)
+       {
+         ignore_WM_CHAR = FALSE;
+         break;
+       }
+
+    wm_char:
+      /* This doesn't handle the rather theorethical case that a window
+       * wants key presses but still wants releases to be propagated,
+       * for instance.
+       */
+      if (k_grab_window != NULL
+         && !k_grab_owner_events)
+       {
+         /* Keyboard is grabbed with owner_events FALSE */
+         GDK_NOTE (EVENTS,
+                   g_print ("grabbed, owner_events FALSE, "
+                            "sending to %#x\n", k_grab_window->xwindow));
+         event->key.window = (GdkWindow *) k_grab_window;
+       }
+      else if (window_private
+              && !(window_private->event_mask & (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK)))
+       {
+         /* Owner window doesn't want it */
+         if (k_grab_window != NULL
+             && k_grab_owner_events)
+           {
+             /* Keyboard is grabbed with owner_events TRUE */
+             GDK_NOTE (EVENTS,
+                       g_print ("grabbed, owner_events TRUE, doesn't want it, "
+                                "sending to %#x\n", k_grab_window->xwindow));
+             event->key.window = (GdkWindow *) k_grab_window;
+           }
+         else
+           {
+             /* Owner doesn't want it, neither is it grabbed, so
+              * propagate to parent.
+              */
+             if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+               g_assert_not_reached (); /* Should've been handled above */
+
+             gdk_window_unref (window);
+             window = window_private->parent;
+             gdk_window_ref (window);
+             window_private = (GdkWindowPrivate *) window;
+             GDK_NOTE (EVENTS,
+                       g_print ("not wanted, not grabbed, sending to %#x\n",
+                                window_private->xwindow));
+             goto wm_char;
+           }
+       }
+      
+      return_val = window_private && !window_private->destroyed;
+      if (return_val && (window_private->event_mask & GDK_KEY_RELEASE_MASK))
+       {
+         /* Return the release event, and maybe append the press
+          * event to the queued_events list (from which it will vbe
+          * fetched before the release event).
+          */
+         event->key.type = GDK_KEY_RELEASE;
+         event->key.keyval = xevent->wParam;
+         event->key.window = window;
+         event->key.time = xevent->time;
+         event->key.state = 0;
+         if (GetKeyState (VK_SHIFT) < 0)
+           event->key.state |= GDK_SHIFT_MASK;
+         if (GetKeyState (VK_CAPITAL) & 0x1)
+           event->key.state |= GDK_LOCK_MASK;
+         if (is_AltGr_key)
+           ;
+         else if (GetKeyState (VK_CONTROL) < 0)
+           {
+             event->key.state |= GDK_CONTROL_MASK;
+             if (event->key.keyval < ' ')
+               event->key.keyval += '@';
+           }
+         else if (event->key.keyval < ' ')
+           {
+             event->key.state |= GDK_CONTROL_MASK;
+             event->key.keyval += '@';
+           }
+         if (!is_AltGr_key && GetKeyState (VK_MENU) < 0)
+           event->key.state |= GDK_MOD1_MASK;
+         event->key.string = g_strdup (" ");
+         event->key.length = 1;
+         event->key.string[0] = xevent->wParam; /* ??? */
+
+         if (window_private->event_mask & GDK_KEY_PRESS_MASK)
+           {
+             /* Append also a GDK_KEY_PRESS event to the pushback list.  */
+             GdkEvent *event2 = gdk_event_copy (event);
+             event2->key.type = GDK_KEY_PRESS;
+             charcount = xevent->lParam & 0xFFFF;
+             if (charcount > sizeof (buf)- 1)
+               charcount = sizeof (buf) - 1;
+             g_free (event2->key.string);
+             event2->key.string = g_malloc (charcount);
+             for (i = 0; i < charcount; i++)
+               event2->key.string[i] = event->key.keyval;
+             event2->key.length = charcount;
+
+             gdk_event_queue_append (event2);
+           }
+       }
+      else if (return_val && (window_private->event_mask & GDK_KEY_PRESS_MASK))
+       {
+         /* Return just the GDK_KEY_PRESS event. */
+         event->key.type = GDK_KEY_PRESS;
+         charcount = xevent->lParam & 0xFFFF;
+         if (charcount > sizeof (buf)- 1)
+           charcount = sizeof (buf) - 1;
+         event->key.keyval = xevent->wParam;
+         event->key.window = window;
+         event->key.time = xevent->time;
+         event->key.state = 0;
+         if (GetKeyState (VK_SHIFT) < 0)
+           event->key.state |= GDK_SHIFT_MASK;
+         if (GetKeyState (VK_CAPITAL) & 0x1)
+           event->key.state |= GDK_LOCK_MASK;
+         if (is_AltGr_key)
+           ;
+         else if (GetKeyState (VK_CONTROL) < 0)
+           {
+             event->key.state |= GDK_CONTROL_MASK;
+             if (event->key.keyval < ' ')
+               event->key.keyval += '@';
+           }
+         else if (event->key.keyval < ' ')
+           {
+             event->key.state |= GDK_CONTROL_MASK;
+             event->key.keyval += '@';
+           }
+         if (!is_AltGr_key && GetKeyState (VK_MENU) < 0)
+           event->key.state |= GDK_MOD1_MASK;
+         event->key.string = g_malloc (charcount);
+         for (i = 0; i < charcount; i++)
+           event->key.string[i] = event->key.keyval;
+         event->key.length = charcount;
+       }
+      else
+       return_val = FALSE;
+      is_AltGr_key = FALSE;
+      break;
+
+    case WM_LBUTTONDOWN:
+      button = 1;
+      goto buttondown0;
+    case WM_MBUTTONDOWN:
+      button = 2;
+      goto buttondown0;
+    case WM_RBUTTONDOWN:
+      button = 3;
+
+      /* Print debugging info.
+       */
+    buttondown0:
+      GDK_NOTE (EVENTS, 
+               g_print ("WM_%cBUTTONDOWN: %#x  x,y: %d %d  button: %d\n",
+                        " LMR"[button],
+                        xevent->hwnd,
+                        LOWORD (xevent->lParam), HIWORD (xevent->lParam),
+                        button));
+
+      if (window_private
+         && (window_private->extension_events != 0)
+         && gdk_input_ignore_core)
+       {
+         GDK_NOTE (EVENTS, g_print ("... ignored\n"));
+         break;
+       }
+
+    buttondown:
+      event->button.type = GDK_BUTTON_PRESS;
+      event->button.window = window;
+      if (window_private)
+       mask = window_private->event_mask;
+      else
+       mask = 0;               /* ??? */
+
+      if (p_grab_window != NULL
+          && !p_grab_owner_events)
+       {
+         /* Pointer is grabbed with owner_events FALSE */
+         GDK_NOTE (EVENTS, g_print ("grabbed, owner_events FALSE\n"));
+         mask = p_grab_event_mask;
+         if (!(mask & GDK_BUTTON_PRESS_MASK))
+           /* Grabber doesn't want it */
+           break;
+         else
+           event->button.window = (GdkWindow *) p_grab_window;
+         GDK_NOTE (EVENTS, g_print ("sending to %#x\n",
+                                    p_grab_window->xwindow));
+       }
+      else if (window_private
+              && !(mask & GDK_BUTTON_PRESS_MASK))
+       {
+         /* Owner window doesn't want it */
+         if (p_grab_window != NULL
+             && p_grab_owner_events)
+           {
+             /* Pointer is grabbed wíth owner_events TRUE */ 
+             GDK_NOTE (EVENTS, g_print ("grabbed, owner_events TRUE, doesn't want it\n"));
+             mask = p_grab_event_mask;
+             if (!(mask & GDK_BUTTON_PRESS_MASK))
+               /* Grabber doesn't want it either */
+               break;
+             else
+               event->button.window = (GdkWindow *) p_grab_window;
+             GDK_NOTE (EVENTS, g_print ("sending to %#x\n",
+                                        p_grab_window->xwindow));
+           }
+         else
+           {
+             /* Owner doesn't want it, neither is it grabbed, so
+              * propagate to parent.
+              */
+             /* Yes, this code is duplicated twice below. So shoot me. */
+             if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+               break;
+             pt.x = LOWORD (xevent->lParam);
+             pt.y = HIWORD (xevent->lParam);
+             ClientToScreen (window_private->xwindow, &pt);
+             gdk_window_unref (window);
+             window = window_private->parent;
+             gdk_window_ref (window);
+             window_private = (GdkWindowPrivate *) window;
+             ScreenToClient (window_private->xwindow, &pt);
+             xevent->lParam = MAKELPARAM (pt.x, pt.y);
+             goto buttondown; /* What did Dijkstra say? */
+           }
+       }
+
+      /* Emulate X11's automatic active grab */
+      if (!p_grab_window)
+       {
+         /* No explicit active grab, let's start one automatically */
+         GDK_NOTE (EVENTS, g_print ("automatic grab started\n"));
+         gdk_pointer_grab (window, TRUE, window_private->event_mask,
+                           NULL, NULL, 0);
+         p_grab_automatic = TRUE;
+       }
+
+      if (window != curWnd)
+       synthesize_crossing_events (window, xevent);
+
+      event->button.time = xevent->time;
+      event->button.x = LOWORD (xevent->lParam);
+      event->button.y = HIWORD (xevent->lParam);
+      event->button.x_root = (gfloat)xevent->pt.x;
+      event->button.y_root = (gfloat)xevent->pt.y;
+      event->button.pressure = 0.5;
+      event->button.xtilt = 0;
+      event->button.ytilt = 0;
+      event->button.state = 0;
+      if (xevent->wParam & MK_CONTROL)
+       event->button.state |= GDK_CONTROL_MASK;
+      if (xevent->wParam & MK_LBUTTON)
+       event->button.state |= GDK_BUTTON1_MASK;
+      if (xevent->wParam & MK_MBUTTON)
+       event->button.state |= GDK_BUTTON2_MASK;
+      if (xevent->wParam & MK_RBUTTON)
+       event->button.state |= GDK_BUTTON3_MASK;
+      if (xevent->wParam & MK_SHIFT)
+       event->button.state |= GDK_SHIFT_MASK;
+      if (GetKeyState (VK_MENU) < 0)
+       event->button.state |= GDK_MOD1_MASK;
+      if (GetKeyState (VK_CAPITAL) & 0x1)
+       event->button.state |= GDK_LOCK_MASK;
+      event->button.button = button;
+      event->button.source = GDK_SOURCE_MOUSE;
+      event->button.deviceid = GDK_CORE_POINTER;
+
+      if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
+         (event->button.window == button_window[1]) &&
+         (event->button.button == button_number[1]))
+       {
+         gdk_synthesize_click (event, 3);
+
+         button_click_time[1] = 0;
+         button_click_time[0] = 0;
+         button_window[1] = NULL;
+         button_window[0] = 0;
+         button_number[1] = -1;
+         button_number[0] = -1;
+       }
+      else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
+              (event->button.window == button_window[0]) &&
+              (event->button.button == button_number[0]))
+       {
+         gdk_synthesize_click (event, 2);
+
+         button_click_time[1] = button_click_time[0];
+         button_click_time[0] = event->button.time;
+         button_window[1] = button_window[0];
+         button_window[0] = event->button.window;
+         button_number[1] = button_number[0];
+         button_number[0] = event->button.button;
+       }
+      else
+       {
+         button_click_time[1] = 0;
+         button_click_time[0] = event->button.time;
+         button_window[1] = NULL;
+         button_window[0] = event->button.window;
+         button_number[1] = -1;
+         button_number[0] = event->button.button;
+       }
+      return_val = window_private && !window_private->destroyed;
+      if (return_val
+         && p_grab_window != NULL
+         && event->any.window == (GdkWindow *) p_grab_window
+         && p_grab_window != window_private)
+       {
+         /* Translate coordinates to grabber */
+         pt.x = event->button.x;
+         pt.y = event->button.y;
+         ClientToScreen (window_private->xwindow, &pt);
+         ScreenToClient (p_grab_window->xwindow, &pt);
+         event->button.x = pt.x;
+         event->button.y = pt.y;
+         GDK_NOTE (EVENTS, g_print ("New coords are +%d+%d\n", pt.x, pt.y));
+       }
+      break;
+
+    case WM_LBUTTONUP:
+      button = 1;
+      goto buttonup0;
+    case WM_MBUTTONUP:
+      button = 2;
+      goto buttonup0;
+    case WM_RBUTTONUP:
+      button = 3;
+
+      /* Print debugging info.
+       */
+    buttonup0:
+      GDK_NOTE (EVENTS, 
+               g_print ("WM_%cBUTTONUP: %#x  x,y: %d %d  button: %d\n",
+                        " LMR"[button],
+                        xevent->hwnd,
+                        LOWORD (xevent->lParam), HIWORD (xevent->lParam),
+                        button));
+
+      if (window_private
+         && (window_private->extension_events != 0)
+         && gdk_input_ignore_core)
+       {
+         GDK_NOTE (EVENTS, g_print ("... ignored\n"));
+         break;
+       }
+
+    buttonup:
+      event->button.type = GDK_BUTTON_RELEASE;
+      event->button.window = window;
+      if (window_private)
+       mask = window_private->event_mask;
+      else
+       mask = 0;
+
+      if (p_grab_window != NULL
+          && !p_grab_owner_events)
+       {
+         /* Pointer is grabbed with owner_events FALSE */
+         GDK_NOTE (EVENTS, g_print ("grabbed, owner_events FALSE\n"));
+         mask = p_grab_event_mask;
+         if (!(mask & GDK_BUTTON_RELEASE_MASK))
+           /* Grabber doesn't want it */
+           break;
+         else
+           event->button.window = (GdkWindow *) p_grab_window;
+         GDK_NOTE (EVENTS, g_print ("sending to %#x\n",
+                                    p_grab_window->xwindow));
+       }
+      else if (window_private
+              && !(mask & GDK_BUTTON_RELEASE_MASK))
+       {
+         /* Owner window doesn't want it */
+         if (p_grab_window != NULL
+             && p_grab_owner_events)
+           {
+             /* Pointer is grabbed wíth owner_events TRUE */
+             GDK_NOTE (EVENTS, g_print ("grabbed, owner_events TRUE, doesn't want it\n"));
+             mask = p_grab_event_mask;
+             if (!(mask & GDK_BUTTON_RELEASE_MASK))
+               /* Grabber doesn't want it */
+               break;
+             else
+               event->button.window = (GdkWindow *) p_grab_window;
+             GDK_NOTE (EVENTS, g_print ("sending to %#x\n",
+                                        p_grab_window->xwindow));
+           }
+         else
+           {
+             /* Owner doesn't want it, neither is it grabbed, so
+              * propagate to parent.
+              */
+             if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+               break;
+             pt.x = LOWORD (xevent->lParam);
+             pt.y = HIWORD (xevent->lParam);
+             ClientToScreen (window_private->xwindow, &pt);
+             gdk_window_unref (window);
+             window = window_private->parent;
+             gdk_window_ref (window);
+             window_private = (GdkWindowPrivate *) window;
+             ScreenToClient (window_private->xwindow, &pt);
+             xevent->lParam = MAKELPARAM (pt.x, pt.y);
+             goto buttonup;
+           }
+       }
+
+      if (window != curWnd)
+       synthesize_crossing_events (window, xevent);
+
+      event->button.time = xevent->time;
+      event->button.x = LOWORD (xevent->lParam);
+      event->button.y = HIWORD (xevent->lParam);
+      event->button.x_root = (gfloat)xevent->pt.x;
+      event->button.y_root = (gfloat)xevent->pt.y;
+      event->button.pressure = 0.5;
+      event->button.xtilt = 0;
+      event->button.ytilt = 0;
+      event->button.state = 0;
+      if (xevent->wParam & MK_CONTROL)
+       event->button.state |= GDK_CONTROL_MASK;
+      if (xevent->wParam & MK_LBUTTON)
+       event->button.state |= GDK_BUTTON1_MASK;
+      if (xevent->wParam & MK_MBUTTON)
+       event->button.state |= GDK_BUTTON2_MASK;
+      if (xevent->wParam & MK_RBUTTON)
+       event->button.state |= GDK_BUTTON3_MASK;
+      if (xevent->wParam & MK_SHIFT)
+       event->button.state |= GDK_SHIFT_MASK;
+      event->button.button = button;
+      event->button.source = GDK_SOURCE_MOUSE;
+      event->button.deviceid = GDK_CORE_POINTER;
+      return_val = window_private && !window_private->destroyed;
+      if (return_val
+         && p_grab_window != NULL
+         && event->any.window == (GdkWindow *) p_grab_window
+         && p_grab_window != window_private)
+       {
+         /* Translate coordinates to grabber */
+         pt.x = event->button.x;
+         pt.y = event->button.y;
+         ClientToScreen (window_private->xwindow, &pt);
+         ScreenToClient (p_grab_window->xwindow, &pt);
+         event->button.x = pt.x;
+         event->button.y = pt.y;
+         GDK_NOTE (EVENTS, g_print ("New coords are +%d+%d\n", pt.x, pt.y));
+       }
+      if (p_grab_window != NULL
+         && p_grab_automatic
+         && (event->button.state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) == 0)
+       gdk_pointer_ungrab (0);
+      break;
+
+    case WM_MOUSEMOVE:
+      /* Print debugging info.
+       */
+      GDK_NOTE (EVENTS,
+               g_print ("WM_MOUSEMOVE: %#x  %#x +%d+%d\n",
+                        xevent->hwnd, xevent->wParam,
+                        LOWORD (xevent->lParam), HIWORD (xevent->lParam)));
+
+#if 0
+      /* Try hard not to generate events for windows that shouldn't
+        get any.  This is hard because we don't want pushbuttons to
+        highlight when the cursor moves over them if the window is
+        inactive. We dont want tooltips windows to be active. OTOH,
+        also menus are popup windows, but they definitely should
+        get events. Aw shit. Skip this.
+       */
+      dwStyle = GetWindowLong (xevent->hwnd, GWL_STYLE);
+      if (active == NULL ||
+         !(active == xevent->hwnd
+           || (dwStyle & WS_POPUP)
+           || IsChild (active, xevent->hwnd)))
+       break;
+#else
+      { /* HB: only process mouse move messages
+         * if we own the active window.
+         */
+         DWORD ProcessID_ActWin;
+         DWORD ProcessID_this;
+
+         GetWindowThreadProcessId(GetActiveWindow(), &ProcessID_ActWin);
+         GetWindowThreadProcessId(xevent->hwnd, &ProcessID_this);
+         if (ProcessID_ActWin != ProcessID_this)
+          break;
+     }
+#endif
+      if (window != curWnd)
+       synthesize_crossing_events (window, xevent);
+
+      if (window_private
+         && (window_private->extension_events != 0)
+         && gdk_input_ignore_core)
+       {
+         GDK_NOTE (EVENTS, g_print ("... ignored\n"));
+         break;
+       }
+
+    mousemotion:
+      event->motion.type = GDK_MOTION_NOTIFY;
+      event->motion.window = window;
+      if (window_private)
+       mask = window_private->event_mask;
+      else
+       mask = 0;
+
+      if (p_grab_window
+         && !p_grab_owner_events)
+       {
+         /* Pointer is grabbed with owner_events FALSE */
+         GDK_NOTE (EVENTS,
+                   g_print ("grabbed, owner_events FALSE\n"));
+         mask = p_grab_event_mask;
+         if (!((mask & GDK_POINTER_MOTION_MASK)
+               || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))
+                   && (mask & GDK_BUTTON_MOTION_MASK))
+               || ((xevent->wParam & MK_LBUTTON)
+                   && (mask & GDK_BUTTON1_MOTION_MASK))
+               || ((xevent->wParam & MK_MBUTTON)
+                   && (mask & GDK_BUTTON2_MOTION_MASK))
+               || ((xevent->wParam & MK_RBUTTON)
+                   && (mask & GDK_BUTTON3_MOTION_MASK))))
+           break;
+         else
+           event->motion.window = (GdkWindow *) p_grab_window;
+         GDK_NOTE (EVENTS, g_print ("sending to %#x\n",
+                                    p_grab_window->xwindow));
+       }
+      else if (window_private
+              && !((mask & GDK_POINTER_MOTION_MASK)
+                   || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))
+                       && (mask & GDK_BUTTON_MOTION_MASK))
+                   || ((xevent->wParam & MK_LBUTTON)
+                       && (mask & GDK_BUTTON1_MOTION_MASK))
+                   || ((xevent->wParam & MK_MBUTTON)
+                       && (mask & GDK_BUTTON2_MOTION_MASK))
+                   || ((xevent->wParam & MK_RBUTTON)
+                       && (mask & GDK_BUTTON3_MOTION_MASK))))
+       {
+         /* Owner window doesn't want it */
+         if (p_grab_window != NULL
+             && p_grab_owner_events)
+           {
+             /* Pointer is grabbed wíth owner_events TRUE */
+             GDK_NOTE (EVENTS, g_print ("grabbed, owner_events TRUE, doesn't want it\n"));
+             mask = p_grab_event_mask;
+             if (!((p_grab_event_mask & GDK_POINTER_MOTION_MASK)
+                   || ((xevent->wParam & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))
+                       && (mask & GDK_BUTTON_MOTION_MASK))
+                   || ((xevent->wParam & MK_LBUTTON)
+                       && (mask & GDK_BUTTON1_MOTION_MASK))
+                   || ((xevent->wParam & MK_MBUTTON)
+                       && (mask & GDK_BUTTON2_MOTION_MASK))
+                   || ((xevent->wParam & MK_RBUTTON)
+                       && (mask & GDK_BUTTON3_MOTION_MASK))))
+               /* Grabber doesn't want it either */
+               break;
+             else
+               event->motion.window = (GdkWindow *) p_grab_window;
+             GDK_NOTE (EVENTS, g_print ("sending to %#x\n",
+                                        p_grab_window->xwindow));
+           }
+         else
+           {
+             /* Owner doesn't want it, neither is it grabbed, so
+              * propagate to parent.
+              */
+             if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+               break;
+             pt.x = LOWORD (xevent->lParam);
+             pt.y = HIWORD (xevent->lParam);
+             ClientToScreen (window_private->xwindow, &pt);
+             gdk_window_unref (window);
+             window = window_private->parent;
+             gdk_window_ref (window);
+             window_private = (GdkWindowPrivate *) window;
+             ScreenToClient (window_private->xwindow, &pt);
+             xevent->lParam = MAKELPARAM (pt.x, pt.y);
+             GDK_NOTE (EVENTS, g_print ("propagating to %#x\n",
+                                        window_private->xwindow));
+             goto mousemotion;
+           }
+       }
+
+      event->motion.time = xevent->time;
+      event->motion.x = curX = LOWORD (xevent->lParam);
+      event->motion.y = curY = HIWORD (xevent->lParam);
+      event->motion.x_root = xevent->pt.x;
+      event->motion.y_root = xevent->pt.y;
+      curXroot = event->motion.x_root;
+      curYroot = event->motion.y_root;
+      event->motion.pressure = 0.5;
+      event->motion.xtilt = 0;
+      event->motion.ytilt = 0;
+      event->button.state = 0;
+      if (xevent->wParam & MK_CONTROL)
+       event->button.state |= GDK_CONTROL_MASK;
+      if (xevent->wParam & MK_LBUTTON)
+       event->button.state |= GDK_BUTTON1_MASK;
+      if (xevent->wParam & MK_MBUTTON)
+       event->button.state |= GDK_BUTTON2_MASK;
+      if (xevent->wParam & MK_RBUTTON)
+       event->button.state |= GDK_BUTTON3_MASK;
+      if (xevent->wParam & MK_SHIFT)
+       event->button.state |= GDK_SHIFT_MASK;
+      if (mask & GDK_POINTER_MOTION_HINT_MASK)
+       event->motion.is_hint = NotifyHint;
+      else
+       event->motion.is_hint = NotifyNormal;
+      event->motion.source = GDK_SOURCE_MOUSE;
+      event->motion.deviceid = GDK_CORE_POINTER;
+
+      return_val = window_private && !window_private->destroyed;
+      if (return_val
+         && p_grab_window != NULL
+         && event->any.window == (GdkWindow *) p_grab_window
+         && p_grab_window != window_private)
+       {
+         /* Translate coordinates to grabber */
+         pt.x = event->motion.x;
+         pt.y = event->motion.y;
+         ClientToScreen (window_private->xwindow, &pt);
+         ScreenToClient (p_grab_window->xwindow, &pt);
+         event->motion.x = pt.x;
+         event->motion.y = pt.y;
+         GDK_NOTE (EVENTS, g_print ("New coords are +%d+%d\n", pt.x, pt.y));
+       }
+      break;
+
+    case WM_NCMOUSEMOVE:
+      /* Print debugging info.  */
+      GDK_NOTE (EVENTS,
+               g_print ("WM_NCMOUSEMOVE: %#x  x,y: %d %d\n",
+                        xevent->hwnd,
+                        LOWORD (xevent->lParam), HIWORD (xevent->lParam)));
+#if 0
+      if (active == NULL || active != xevent->hwnd)
+       break;
+#endif
+      curWnd_private = (GdkWindowPrivate *) curWnd;
+      if (curWnd != NULL
+         && (curWnd_private->event_mask & GDK_LEAVE_NOTIFY_MASK))
+       {
+         GDK_NOTE (EVENTS, g_print ("synthesizing LEAVE_NOTIFY event\n"));
+
+         event->crossing.type = GDK_LEAVE_NOTIFY;
+         event->crossing.window = curWnd;
+         event->crossing.subwindow = NULL;
+         event->crossing.time = xevent->time;
+         event->crossing.x = curX;
+         event->crossing.y = curY;
+         event->crossing.x_root = curXroot;
+         event->crossing.y_root = curYroot;
+         event->crossing.mode = GDK_CROSSING_NORMAL;
+         event->crossing.detail = GDK_NOTIFY_UNKNOWN;
+
+         event->crossing.focus = TRUE; /* ??? */
+         event->crossing.state = 0; /* ??? */
+         gdk_window_unref (curWnd);
+         curWnd = NULL;
+
+         return_val = TRUE;
+       }
+      break;
+
+    case WM_SETFOCUS:
+    case WM_KILLFOCUS:
+      if (window_private
+         && !(window_private->event_mask & GDK_FOCUS_CHANGE_MASK))
+       break;
+
+      GDK_NOTE (EVENTS, g_print ("WM_%sFOCUS: %#x\n",
+                                (xevent->message == WM_SETFOCUS ? "SET" : "KILL"),
+                                xevent->hwnd));
+      
+      event->focus_change.type = GDK_FOCUS_CHANGE;
+      event->focus_change.window = window;
+      event->focus_change.in = (xevent->message == WM_SETFOCUS);
+      return_val = window_private && !window_private->destroyed;
+      break;
+#if 0
+    case WM_ACTIVATE:
+      GDK_NOTE (EVENTS, g_print ("WM_ACTIVATE: %#x  %d\n",
+                                xevent->hwnd, LOWORD (xevent->wParam)));
+      if (LOWORD (xevent->wParam) == WA_INACTIVE)
+       active = (HWND) xevent->lParam;
+      else
+       active = xevent->hwnd;
+      break;
+#endif
+    case WM_ERASEBKGND:
+      GDK_NOTE (EVENTS, g_print ("WM_ERASEBKGND: %#x  dc %#x\n",
+                                xevent->hwnd, xevent->wParam));
+      
+      if (!window_private || window_private->destroyed)
+       break;
+      colormap_private = (GdkColormapPrivate *) window_private->colormap;
+      hdc = (HDC) xevent->wParam;
+      if (colormap_private
+         && colormap_private->xcolormap->rc_palette)
+       {
+         int k;
+
+         if (SelectPalette (hdc,  colormap_private->xcolormap->palette,
+                            FALSE) == NULL)
+           g_warning ("WM_ERASEBKGND: SelectPalette failed");
+         if ((k = RealizePalette (hdc)) == GDI_ERROR)
+           g_warning ("WM_ERASEBKGND: RealizePalette failed");
+#if 0
+         g_print ("WM_ERASEBKGND: selected %#x, realized %d colors\n",
+                  colormap_private->xcolormap->palette, k);
+#endif
+       }
+      *ret_val_flagp = TRUE;
+      *ret_valp = 1;
+
+      if (window_private->bg_type == GDK_WIN32_BG_TRANSPARENT)
+       break;
+
+      if (window_private->bg_type == GDK_WIN32_BG_PARENT_RELATIVE)
+       {
+         /* If this window should have the same background as the
+          * parent, fetch the parent. (And if the same goes for
+          * the parent, fetch the grandparent, etc.)
+          */
+         while (window_private
+                && window_private->bg_type == GDK_WIN32_BG_PARENT_RELATIVE)
+           window_private = (GdkWindowPrivate *) window_private->parent;
+       }
+
+      if (window_private->bg_type == GDK_WIN32_BG_PIXEL)
+       {
+         COLORREF bg;
+         GDK_NOTE (EVENTS, g_print ("... BG_PIXEL %s\n",
+                                    gdk_color_to_string (&window_private->bg_pixel)));
+         GetClipBox (hdc, &rect);
+#ifdef MULTIPLE_WINDOW_CLASSES
+         bg = PALETTEINDEX (window_private->bg_pixel.pixel);
+#else
+         bg = GetNearestColor (hdc, RGB (window_private->bg_pixel.red >> 8,
+                                         window_private->bg_pixel.green >> 8,
+                                         window_private->bg_pixel.blue >> 8));
+#endif
+         hbr = CreateSolidBrush (bg);
+#if 0
+         g_print ("... CreateSolidBrush (%.08x) = %.08x\n", bg, hbr);
+#endif
+         if (!FillRect (hdc, &rect, hbr))
+           g_warning ("WM_ERASEBKGND: FillRect failed");
+         DeleteObject (hbr);
+       }
+      else if (window_private->bg_type == GDK_WIN32_BG_PIXMAP)
+       {
+         GdkPixmapPrivate *pixmap_private;
+         HDC bgdc;
+         HGDIOBJ oldbitmap;
+
+         pixmap_private = (GdkPixmapPrivate *) window_private->bg_pixmap;
+         GetClipBox (hdc, &rect);
+
+         if (pixmap_private->width <= 8
+             && pixmap_private->height <= 8)
+           {
+             GDK_NOTE (EVENTS, g_print ("...small pixmap, using brush\n"));
+             hbr = CreatePatternBrush (pixmap_private->xwindow);
+             if (!FillRect (hdc, &rect, hbr))
+               g_warning ("WM_ERASEBKGND: FillRect failed");
+             DeleteObject (hbr);
+           }
+         else
+           {
+             GDK_NOTE (EVENTS,
+                       g_print ("...blitting pixmap %#x (%dx%d) "
+                                "all over the place,\n"
+                                "...clip box = %dx%d@+%d+%d\n",
+                                pixmap_private->xwindow,
+                                pixmap_private->width, pixmap_private->height,
+                                rect.right - rect.left, rect.bottom - rect.top,
+                                rect.left, rect.top));
+
+             if (!(bgdc = CreateCompatibleDC (hdc)))
+               {
+                 g_warning ("WM_ERASEBKGND: CreateCompatibleDC failed");
+                 break;
+               }
+             if (!(oldbitmap = SelectObject (bgdc, pixmap_private->xwindow)))
+               {
+                 g_warning ("WM_ERASEBKGND: SelectObject failed");
+                 DeleteDC (bgdc);
+                 break;
+               }
+             i = 0;
+             while (i < rect.right)
+               {
+                 j = 0;
+                 while (j < rect.bottom)
+                   {
+                     if (i + pixmap_private->width >= rect.left
+                         && j + pixmap_private->height >= rect.top)
+                       {
+                         if (!BitBlt (hdc, i, j,
+                                      pixmap_private->width, pixmap_private->height,
+                                      bgdc, 0, 0, SRCCOPY))
+                           {
+                             g_warning ("WM_ERASEBKGND: BitBlt failed");
+                             goto loopexit;
+                           }
+                       }
+                     j += pixmap_private->height;
+                   }
+                 i += pixmap_private->width;
+               }
+           loopexit:
+             SelectObject (bgdc, oldbitmap);
+             DeleteDC (bgdc);
+           }
+       }
+      else
+       {
+         GDK_NOTE (EVENTS, g_print ("... BLACK_BRUSH (?)\n"));
+#ifdef MULTIPLE_WINDOW_CLASSES
+         hbr = (HBRUSH) GetClassLong (window_private->xwindow,
+                                      GCL_HBRBACKGROUND);
+#else
+         hbr = GetStockObject (BLACK_BRUSH);
+#endif
+         GetClipBox (hdc, &rect);
+         if (!FillRect (hdc, &rect, hbr))
+           g_warning ("WM_ERASEBKGND: FillRect failed");
+       }
+      break;
+
+    case WM_PAINT:
+      GDK_NOTE (EVENTS, g_print ("WM_PAINT: %#x\n", xevent->hwnd));
+      hdc = BeginPaint (xevent->hwnd, &paintstruct);
+
+      /* Print debugging info.
+       */
+      GDK_NOTE (EVENTS,
+               g_print ("...WM_PAINT: %#x  %dx%d@+%d+%d %s dc %#x\n",
+                        xevent->hwnd,
+                        paintstruct.rcPaint.right - paintstruct.rcPaint.left,
+                        paintstruct.rcPaint.bottom - paintstruct.rcPaint.top,
+                        paintstruct.rcPaint.left, paintstruct.rcPaint.top,
+                        (paintstruct.fErase ? "erase" : ""),
+                        hdc));
+
+      EndPaint (xevent->hwnd, &paintstruct);
+
+      if (window_private
+         && !(window_private->event_mask & GDK_EXPOSURE_MASK))
+       break;
+
+      event->expose.type = GDK_EXPOSE;
+      event->expose.window = window;
+      event->expose.area.x = paintstruct.rcPaint.left;
+      event->expose.area.y = paintstruct.rcPaint.top;
+      event->expose.area.width = paintstruct.rcPaint.right - paintstruct.rcPaint.left;
+      event->expose.area.height = paintstruct.rcPaint.bottom - paintstruct.rcPaint.top;
+      event->expose.count = 1;
+
+      return_val = window_private && !window_private->destroyed;
+      break;
+
+#ifndef MULTIPLE_WINDOW_CLASSES
+    case WM_SETCURSOR:
+      GDK_NOTE (EVENTS, g_print ("WM_SETCURSOR: %#x %#x %#x\n",
+                                xevent->hwnd,
+                                LOWORD (xevent->lParam), HIWORD (xevent->lParam)));
+
+      return_val = FALSE;
+      if (LOWORD (xevent->lParam) != HTCLIENT)
+       break;
+      if (p_grab_window != NULL && p_grab_cursor != NULL)
+       SetCursor (p_grab_cursor);
+      else if (window_private
+              && !window_private->destroyed
+              && window_private->xcursor)
+       SetCursor (window_private->xcursor);
+      *ret_val_flagp = TRUE;
+      *ret_valp = FALSE;
+      break;
+#endif
+
+#if 0
+    case WM_QUERYOPEN:
+      GDK_NOTE (EVENTS, g_print ("WM_QUERYOPEN: %#x\n",
+                                xevent->hwnd));
+      *ret_val_flagp = TRUE;
+      *ret_valp = TRUE;
+
+      if (window_private
+         && !(window_private->event_mask & GDK_STRUCTURE_MASK))
+       break;
+
+      event->any.type = GDK_MAP;
+      event->any.window = window;
+
+      return_val = window_private && !window_private->destroyed;
+      break;
+#endif
+
+#if 1
+    case WM_SHOWWINDOW:
+      /* Print debugging info.
+       */
+      GDK_NOTE (EVENTS, g_print ("WM_SHOWWINDOW: %#x  %d\n",
+                                xevent->hwnd,
+                                xevent->wParam));
+
+      if (window_private
+         && !(window_private->event_mask & GDK_STRUCTURE_MASK))
+       break;
+
+      event->any.type = (xevent->wParam ? GDK_MAP : GDK_UNMAP);
+      event->any.window = window;
+
+      if (event->any.type == GDK_UNMAP
+         && p_grab_window == window_private)
+       gdk_pointer_ungrab (xevent->time);
+
+      if (event->any.type == GDK_UNMAP
+         && k_grab_window == window_private)
+       gdk_keyboard_ungrab (xevent->time);
+
+      return_val = window_private && !window_private->destroyed;
+      break;
+#endif
+    case WM_SIZE:
+      /* Print debugging info.
+       */
+      GDK_NOTE (EVENTS,
+               g_print ("WM_SIZE: %#x  %s %dx%d\n",
+                        xevent->hwnd,
+                        (xevent->wParam == SIZE_MAXHIDE ? "MAXHIDE" :
+                         (xevent->wParam == SIZE_MAXIMIZED ? "MAXIMIZED" :
+                          (xevent->wParam == SIZE_MAXSHOW ? "MAXSHOW" :
+                           (xevent->wParam == SIZE_MINIMIZED ? "MINIMIZED" :
+                            (xevent->wParam == SIZE_RESTORED ? "RESTORED" : "?"))))),
+                        LOWORD (xevent->lParam), HIWORD (xevent->lParam)));
+
+      if (window_private
+         && !(window_private->event_mask & GDK_STRUCTURE_MASK))
+       break;
+      if (window_private != NULL
+         && xevent->wParam == SIZE_MINIMIZED)
+       {
+#if 1
+         event->any.type = GDK_UNMAP;
+         event->any.window = window;
+
+         if (p_grab_window == window_private)
+           gdk_pointer_ungrab (xevent->time);
+
+         if (k_grab_window == window_private)
+           gdk_keyboard_ungrab (xevent->time);
+
+         return_val = !window_private->destroyed;
+#endif
+       }
+      else if (window_private != NULL
+              && (xevent->wParam == SIZE_RESTORED
+                  || xevent->wParam == SIZE_MAXIMIZED)
+#if 1
+              && window_private->window_type != GDK_WINDOW_CHILD
+#endif
+                                                                )
+       {
+         if (LOWORD (xevent->lParam) == 0)
+           break;
+
+         event->configure.type = GDK_CONFIGURE;
+         event->configure.window = window;
+         pt.x = 0;
+         pt.y = 0;
+         ClientToScreen (xevent->hwnd, &pt);
+         event->configure.x = pt.x;
+         event->configure.y = pt.y;
+         event->configure.width = LOWORD (xevent->lParam);
+         event->configure.height = HIWORD (xevent->lParam);
+         window_private->x = event->configure.x;
+         window_private->y = event->configure.y;
+         window_private->width = event->configure.width;
+         window_private->height = event->configure.height;
+         if (window_private->resize_count > 1)
+           window_private->resize_count -= 1;
+         
+         return_val = !window_private->destroyed;
+         if (return_val
+             && window_private->extension_events != 0
+             && gdk_input_vtable.configure_event)
+           gdk_input_vtable.configure_event (&event->configure, window);
+       }
+      break;
+
+    case WM_SIZING:
+      GDK_NOTE (EVENTS, g_print ("WM_SIZING: %#x\n", xevent->hwnd));
+      if (ret_val_flagp == NULL)
+         g_warning ("ret_val_flagp is NULL but we got a WM_SIZING?");
+      else if (window_private != NULL
+              && window_private->hint_flags &
+              (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE))
+       {
+         LPRECT lprc = (LPRECT) xevent->lParam;
+
+         if (window_private->hint_flags & GDK_HINT_MIN_SIZE)
+           {
+             gint w = lprc->right - lprc->left;
+             gint h = lprc->bottom - lprc->top;
+
+             if (w < window_private->hint_min_width)
+               {
+                 if (xevent->wParam == WMSZ_BOTTOMLEFT
+                     || xevent->wParam == WMSZ_LEFT
+                     || xevent->wParam == WMSZ_TOPLEFT)
+                   lprc->left = lprc->right - window_private->hint_min_width;
+                 else
+                   lprc->right = lprc->left + window_private->hint_min_width;
+                 *ret_val_flagp = TRUE;
+                 *ret_valp = TRUE;
+               }
+             if (h < window_private->hint_min_height)
+               {
+                 if (xevent->wParam == WMSZ_BOTTOMLEFT
+                     || xevent->wParam == WMSZ_BOTTOM
+                     || xevent->wParam == WMSZ_BOTTOMRIGHT)
+                   lprc->bottom = lprc->top + window_private->hint_min_height;
+                 else
+                   lprc->top = lprc->bottom - window_private->hint_min_height;
+                 *ret_val_flagp = TRUE;
+                 *ret_valp = TRUE;
+               }
+           }
+         if (window_private->hint_flags & GDK_HINT_MAX_SIZE)
+           {
+             gint w = lprc->right - lprc->left;
+             gint h = lprc->bottom - lprc->top;
+
+             if (w > window_private->hint_max_width)
+               {
+                 if (xevent->wParam == WMSZ_BOTTOMLEFT
+                     || xevent->wParam == WMSZ_LEFT
+                     || xevent->wParam == WMSZ_TOPLEFT)
+                   lprc->left = lprc->right - window_private->hint_max_width;
+                 else
+                   lprc->right = lprc->left + window_private->hint_max_width;
+                 *ret_val_flagp = TRUE;
+                 *ret_valp = TRUE;
+               }
+             if (h > window_private->hint_max_height)
+               {
+                 if (xevent->wParam == WMSZ_BOTTOMLEFT
+                     || xevent->wParam == WMSZ_BOTTOM
+                     || xevent->wParam == WMSZ_BOTTOMRIGHT)
+                   lprc->bottom = lprc->top + window_private->hint_max_height;
+                 else
+                   lprc->top = lprc->bottom - window_private->hint_max_height;
+                 *ret_val_flagp = TRUE;
+                 *ret_valp = TRUE;
+               }
+           }
+       }
+      break;
+
+    case WM_MOVE:
+      GDK_NOTE (EVENTS, g_print ("WM_MOVE: %#x  +%d+%d\n",
+                                xevent->hwnd,
+                                LOWORD (xevent->lParam), HIWORD (xevent->lParam)));
+
+      if (window_private
+         && !(window_private->event_mask & GDK_STRUCTURE_MASK))
+       break;
+      if (window_private != NULL
+         && window_private->window_type != GDK_WINDOW_CHILD)
+       {
+         event->configure.type = GDK_CONFIGURE;
+         event->configure.window = window;
+         event->configure.x = LOWORD (xevent->lParam);
+         event->configure.y = HIWORD (xevent->lParam);
+         GetClientRect (xevent->hwnd, &rect);
+         event->configure.width = rect.right;
+         event->configure.height = rect.bottom;
+         window_private->x = event->configure.x;
+         window_private->y = event->configure.y;
+         window_private->width = event->configure.width;
+         window_private->height = event->configure.height;
+         
+         return_val = !window_private->destroyed;
+       }
+      break;
+
+    case WM_CLOSE:
+      GDK_NOTE (EVENTS, g_print ("WM_CLOSE: %#x\n", xevent->hwnd));
+      event->any.type = GDK_DELETE;
+      event->any.window = window;
+      
+      return_val = window_private && !window_private->destroyed;
+      break;
+
+#if 0
+    /* No, don't use delayed rendering after all. It works only if the
+     * delayed SetClipboardData is called from the WindowProc, it
+     * seems. (The #else part below is test code for that. It succeeds
+     * in setting the clipboard data. But if I call SetClipboardData
+     * in gdk_property_change (as a consequence of the
+     * GDK_SELECTION_REQUEST event), it fails.  I deduce that this is
+     * because delayed rendering requires that SetClipboardData is
+     * called in the window procedure.)
+     */
+    case WM_RENDERFORMAT:
+    case WM_RENDERALLFORMATS:
+      flag = FALSE;
+      GDK_NOTE (EVENTS, flag = TRUE);
+      GDK_NOTE (SELECTION, flag = TRUE);
+      if (flag)
+       g_print ("WM_%s: %#x %#x (%s)\n",
+                (xevent->message == WM_RENDERFORMAT ? "RENDERFORMAT" :
+                 "RENDERALLFORMATS"),
+                xevent->hwnd,
+                xevent->wParam,
+                (xevent->wParam == CF_TEXT ? "CF_TEXT" :
+                 (xevent->wParam == CF_DIB ? "CF_DIB" :
+                  (xevent->wParam == CF_UNICODETEXT ? "CF_UNICODETEXT" :
+                   (GetClipboardFormatName (xevent->wParam, buf, sizeof (buf)), buf)))));
+
+#if 0
+      event->selection.type = GDK_SELECTION_REQUEST;
+      event->selection.window = window;
+      event->selection.selection = gdk_clipboard_atom;
+      if (xevent->wParam == CF_TEXT)
+       event->selection.target = GDK_TARGET_STRING;
+      else
+       {
+         GetClipboardFormatName (xevent->wParam, buf, sizeof (buf));
+         event->selection.target = gdk_atom_intern (buf, FALSE);
+       }
+      event->selection.property = gdk_selection_property;
+      event->selection.requestor = (guint32) xevent->hwnd;
+      event->selection.time = xevent->time;
+      return_val = window_private && !window_private->destroyed;
+#else
+      /* Test code, to see if SetClipboardData works when called from
+       * the window procedure.
+       */
+      {
+       HGLOBAL hdata = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE, 10);
+       char *ptr = GlobalLock (hdata);
+       strcpy (ptr, "Huhhaa");
+       GlobalUnlock (hdata);
+       if (!SetClipboardData (CF_TEXT, hdata))
+         g_print ("SetClipboardData failed: %d\n", GetLastError ());
+      }
+      *ret_valp = 0;
+      *ret_val_flagp = TRUE;
+      return_val = FALSE;
+#endif
+      break;
+#endif /* No delayed rendering */
+
+    case WM_DESTROY:
+      GDK_NOTE (EVENTS, g_print ("WM_DESTROY: %#x\n", xevent->hwnd));
+      event->any.type = GDK_DESTROY;
+      event->any.window = window;
+      if (window != NULL && window == curWnd)
+       {
+         gdk_window_unref (curWnd);
+         curWnd = NULL;
+       }
+
+      if (p_grab_window == window_private)
+       gdk_pointer_ungrab (xevent->time);
+
+      if (k_grab_window == window_private)
+       gdk_keyboard_ungrab (xevent->time);
+
+      return_val = window_private && !window_private->destroyed;
+      break;
+
+      /* Handle WINTAB events here, as we know that gdkinput.c will
+       * use the fixed WT_DEFBASE as lcMsgBase, and we thus can use the
+       * constants as case labels.
+       */
+    case WT_PACKET:
+      GDK_NOTE (EVENTS, g_print ("WT_PACKET: %d %#x\n",
+                                xevent->wParam, xevent->lParam));
+      goto wintab;
+      
+    case WT_CSRCHANGE:
+      GDK_NOTE (EVENTS, g_print ("WT_CSRCHANGE: %d %#x\n",
+                                xevent->wParam, xevent->lParam));
+      goto wintab;
+      
+    case WT_PROXIMITY:
+      GDK_NOTE (EVENTS,
+               g_print ("WT_PROXIMITY: %#x %d %d\n",
+                        xevent->wParam,
+                        LOWORD (xevent->lParam), HIWORD (xevent->lParam)));
+    wintab:
+      return_val = gdk_input_vtable.other_event(event, xevent);
+      break;
+    }
+
+bypass_switch:
+
+  if (return_val)
+    {
+      if (event->any.window)
+       gdk_window_ref (event->any.window);
+      if (((event->any.type == GDK_ENTER_NOTIFY) ||
+          (event->any.type == GDK_LEAVE_NOTIFY)) &&
+         (event->crossing.subwindow != NULL))
+       gdk_window_ref (event->crossing.subwindow);
+    }
+  else
+    {
+      /* Mark this event as having no resources to be freed */
+      event->any.window = NULL;
+      event->any.type = GDK_NOTHING;
+    }
+
+  if (window)
+    gdk_window_unref (window);
+  
+  return return_val;
+}
+
+static void
+gdk_events_queue (void)
+{
+  GList *node;
+  GdkEvent *event;
+  MSG msg;
+
+  GDK_NOTE (EVENTS, g_print ("gdk_events_queue: %s\n",
+                            (queued_events ? "yes" : "none")));
+
+  while (!gdk_event_queue_find_first()
+        && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+    {
+      GDK_NOTE (EVENTS, g_print ("gdk_events_queue: got event\n"));
+      TranslateMessage (&msg);
+
+      event = gdk_event_new ();
+      
+      event->any.type = GDK_NOTHING;
+      event->any.window = NULL;
+      event->any.send_event = FALSE;
+
+      ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
+
+      gdk_event_queue_append (event);
+      node = queued_tail;
+
+      if (gdk_event_translate (event, &msg, NULL, NULL))
+         ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
+      else
+       {
+         DefWindowProc (msg.hwnd, msg.message, msg.wParam, msg.lParam);
+         gdk_event_queue_remove_link (node);
+         g_list_free_1 (node);
+         gdk_event_free (event);
+       }
+    }
+}
+
+static gboolean  
+gdk_event_prepare (gpointer  source_data, 
+                  GTimeVal *current_time,
+                  gint     *timeout)
+{
+  MSG msg;
+  gboolean retval;
+  
+  GDK_THREADS_ENTER ();
+
+  *timeout = -1;
+
+  GDK_NOTE (EVENTS, g_print ("gdk_event_prepare\n"));
+
+  retval = (gdk_event_queue_find_first () != NULL)
+             || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
+
+  GDK_THREADS_LEAVE ();
+
+  return retval;
+}
+
+static gboolean  
+gdk_event_check (gpointer  source_data,
+                GTimeVal *current_time)
+{
+  MSG msg;
+  gboolean retval;
+  
+  GDK_NOTE (EVENTS, g_print ("gdk_event_check\n"));
+
+  GDK_THREADS_ENTER ();
+
+  if (event_poll_fd.revents & G_IO_IN)
+    retval = (gdk_event_queue_find_first () != NULL)
+             || PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
+  else
+    retval = FALSE;
+
+  GDK_THREADS_LEAVE ();
+
+  return retval;
+}
+
+static GdkEvent*
+gdk_event_unqueue (void)
+{
+  GdkEvent *event = NULL;
+  GList *tmp_list;
+
+  tmp_list = gdk_event_queue_find_first ();
+
+  if (tmp_list)
+    {
+      event = tmp_list->data;
+      gdk_event_queue_remove_link (tmp_list);
+      g_list_free_1 (tmp_list);
+    }
+
+  return event;
+}
+
+static gboolean  
+gdk_event_dispatch (gpointer  source_data,
+                   GTimeVal *current_time,
+                   gpointer  user_data)
+{
+  GdkEvent *event;
+  GDK_NOTE (EVENTS, g_print ("gdk_event_dispatch\n"));
+
+  GDK_THREADS_ENTER ();
+
+  gdk_events_queue();
+  event = gdk_event_unqueue();
+
+  if (event)
+    {
+      if (event_func)
+       (*event_func) (event, event_data);
+      
+      gdk_event_free (event);
+    }
+  
+  GDK_THREADS_LEAVE ();
+
+  return TRUE;
+}
+
+static void
+gdk_synthesize_click (GdkEvent *event,
+                     gint      nclicks)
+{
+  GdkEvent temp_event;
+  
+  g_return_if_fail (event != NULL);
+  
+  temp_event = *event;
+  temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
+  
+  gdk_event_put (&temp_event);
+}
+
+/* Sends a ClientMessage to all toplevel client windows */
+gboolean
+gdk_event_send_client_message (GdkEvent *event, guint32 xid)
+{
+  /* XXX */
+  return FALSE;
+}
+
+void
+gdk_event_send_clientmessage_toall (GdkEvent *event)
+{
+  /* XXX */
+}
+
diff --git a/gdk/win32/gdkfont-win32.c b/gdk/win32/gdkfont-win32.c
new file mode 100644 (file)
index 0000000..cfe9382
--- /dev/null
@@ -0,0 +1,697 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "gdk.h"
+#include "gdkprivate.h"
+
+GdkFont*
+gdk_font_load (const gchar *font_name)
+{
+  GdkFont *font;
+  GdkFontPrivate *private;
+  LOGFONT logfont;
+  HGDIOBJ oldfont;
+  TEXTMETRIC textmetric;
+  HANDLE *f;
+  DWORD fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet,
+    fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily;
+  const char *lpszFace;
+
+  int numfields, n1, n2, tries;
+  char foundry[32], family[100], weight[32], slant[32], set_width[32],
+    spacing[32], registry[32], encoding[32];
+  char pixel_size[10], point_size[10], res_x[10], res_y[10], avg_width[10];
+  int c;
+  char *p;
+  int nHeight, nWidth, nEscapement, nOrientation, fnWeight;
+  int logpixelsy;
+
+  private = g_new (GdkFontPrivate, 1);
+  font = (GdkFont*) private;
+
+  numfields = sscanf (font_name,
+                     "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n",
+                     foundry,
+                     family,
+                     weight,
+                     slant,
+                     set_width,
+                     &n1);
+  if (numfields == 0)
+    {
+      /* Probably a plain Windows font name */
+      nHeight = 0;
+      nWidth = 0;
+      nEscapement = 0;
+      nOrientation = 0;
+      fnWeight = FW_DONTCARE;
+      fdwItalic = FALSE;
+      fdwUnderline = FALSE;
+      fdwStrikeOut = FALSE;
+      fdwCharSet = ANSI_CHARSET;
+      fdwOutputPrecision = OUT_TT_PRECIS;
+      fdwClipPrecision = CLIP_DEFAULT_PRECIS;
+      fdwQuality = PROOF_QUALITY;
+      fdwPitchAndFamily = DEFAULT_PITCH;
+      lpszFace = font_name;
+    }
+  else if (numfields != 5)
+    {
+      g_warning ("gdk_font_load: font name %s illegal", font_name);
+      g_free (font);
+      return NULL;
+    }
+  else
+    {
+      /* It must be a XLFD name */
+
+      /* Check for hex escapes in the font family,
+       * put in there by gtkfontsel.
+       */
+      p = family;
+      while (*p)
+       {
+         if (*p == '%' && isxdigit (p[1]) && isxdigit (p[2]))
+           {
+             sscanf (p+1, "%2x", &c);
+             *p = c;
+             strcpy (p+1, p+3);
+           }
+         p++;
+       }
+
+      /* Skip add_style which often is empty in the requested font name */
+      while (font_name[n1] && font_name[n1] != '-')
+       n1++;
+      numfields++;
+
+      numfields += sscanf (font_name + n1,
+                          "-%8[^-]-%8[^-]-%8[^-]-%8[^-]-%30[^-]-%8[^-]-%30[^-]-%30[^-]%n",
+                          pixel_size,
+                          point_size,
+                          res_x,
+                          res_y,
+                          spacing,
+                          avg_width,
+                          registry,
+                          encoding,
+                          &n2);
+
+      if (numfields != 14 || font_name[n1 + n2] != '\0')
+       {
+         g_warning ("gdk_font_load: font name %s illegal", font_name);
+         g_free (font);
+         return NULL;
+       }
+
+      logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY);
+
+      if (strcmp (pixel_size, "*") == 0)
+       if (strcmp (point_size, "*") == 0)
+         nHeight = 0;
+       else
+         nHeight = (int) (((double) atoi (point_size))/720.*logpixelsy);
+      else
+       nHeight = atoi (pixel_size);
+
+      nWidth = 0;
+      nEscapement = 0;
+      nOrientation = 0;
+
+      if (g_strcasecmp (weight, "thin") == 0)
+       fnWeight = FW_THIN;
+      else if (g_strcasecmp (weight, "extralight") == 0)
+       fnWeight = FW_EXTRALIGHT;
+      else if (g_strcasecmp (weight, "ultralight") == 0)
+       fnWeight = FW_ULTRALIGHT;
+      else if (g_strcasecmp (weight, "light") == 0)
+       fnWeight = FW_LIGHT;
+      else if (g_strcasecmp (weight, "normal") == 0)
+       fnWeight = FW_NORMAL;
+      else if (g_strcasecmp (weight, "regular") == 0)
+       fnWeight = FW_REGULAR;
+      else if (g_strcasecmp (weight, "medium") == 0)
+       fnWeight = FW_MEDIUM;
+      else if (g_strcasecmp (weight, "semibold") == 0)
+       fnWeight = FW_SEMIBOLD;
+      else if (g_strcasecmp (weight, "demibold") == 0)
+       fnWeight = FW_DEMIBOLD;
+      else if (g_strcasecmp (weight, "bold") == 0)
+       fnWeight = FW_BOLD;
+      else if (g_strcasecmp (weight, "extrabold") == 0)
+       fnWeight = FW_EXTRABOLD;
+      else if (g_strcasecmp (weight, "ultrabold") == 0)
+       fnWeight = FW_ULTRABOLD;
+      else if (g_strcasecmp (weight, "heavy") == 0)
+       fnWeight = FW_HEAVY;
+      else if (g_strcasecmp (weight, "black") == 0)
+       fnWeight = FW_BLACK;
+      else
+       fnWeight = FW_DONTCARE;
+
+      if (g_strcasecmp (slant, "italic") == 0
+         || g_strcasecmp (slant, "oblique") == 0
+         || g_strcasecmp (slant, "i") == 0
+         || g_strcasecmp (slant, "o") == 0)
+       fdwItalic = TRUE;
+      else
+       fdwItalic = FALSE;
+      fdwUnderline = FALSE;
+      fdwStrikeOut = FALSE;
+      if (g_strcasecmp (registry, "iso8859") == 0)
+       if (strcmp (encoding, "1") == 0)
+         fdwCharSet = ANSI_CHARSET;
+       else
+         fdwCharSet = ANSI_CHARSET; /* XXX ??? */
+      else if (g_strcasecmp (registry, "windows") == 0)
+       if (g_strcasecmp (encoding, "symbol") == 0)
+         fdwCharSet = SYMBOL_CHARSET;
+       else if (g_strcasecmp (encoding, "shiftjis") == 0)
+         fdwCharSet = SHIFTJIS_CHARSET;
+       else if (g_strcasecmp (encoding, "gb2312") == 0)
+         fdwCharSet = GB2312_CHARSET;
+       else if (g_strcasecmp (encoding, "hangeul") == 0)
+         fdwCharSet = HANGEUL_CHARSET;
+       else if (g_strcasecmp (encoding, "chinesebig5") == 0)
+         fdwCharSet = CHINESEBIG5_CHARSET;
+       else if (g_strcasecmp (encoding, "johab") == 0)
+         fdwCharSet = JOHAB_CHARSET;
+       else if (g_strcasecmp (encoding, "hebrew") == 0)
+         fdwCharSet = HEBREW_CHARSET;
+       else if (g_strcasecmp (encoding, "arabic") == 0)
+         fdwCharSet = ARABIC_CHARSET;
+       else if (g_strcasecmp (encoding, "greek") == 0)
+         fdwCharSet = GREEK_CHARSET;
+       else if (g_strcasecmp (encoding, "turkish") == 0)
+         fdwCharSet = TURKISH_CHARSET;
+       else if (g_strcasecmp (encoding, "easteurope") == 0)
+         fdwCharSet = EASTEUROPE_CHARSET;
+       else if (g_strcasecmp (encoding, "russian") == 0)
+         fdwCharSet = RUSSIAN_CHARSET;
+       else if (g_strcasecmp (encoding, "mac") == 0)
+         fdwCharSet = MAC_CHARSET;
+       else if (g_strcasecmp (encoding, "baltic") == 0)
+         fdwCharSet = BALTIC_CHARSET;
+       else
+         fdwCharSet = ANSI_CHARSET; /* XXX ??? */
+      else
+       fdwCharSet = ANSI_CHARSET; /* XXX ??? */
+      fdwOutputPrecision = OUT_TT_PRECIS;
+      fdwClipPrecision = CLIP_DEFAULT_PRECIS;
+      fdwQuality = PROOF_QUALITY;
+      if (g_strcasecmp (spacing, "m") == 0)
+       fdwPitchAndFamily = FIXED_PITCH;
+      else if (g_strcasecmp (spacing, "p") == 0)
+       fdwPitchAndFamily = VARIABLE_PITCH;
+      else 
+       fdwPitchAndFamily = DEFAULT_PITCH;
+      lpszFace = family;
+    }
+
+  for (tries = 0; ; tries++)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_font_load: trying CreateFont(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%#.02x,\"%s\")\n",
+                              nHeight, nWidth, nEscapement, nOrientation,
+                              fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
+                              fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
+                              fdwQuality, fdwPitchAndFamily, lpszFace));
+      if ((private->xfont =
+          CreateFont (nHeight, nWidth, nEscapement, nOrientation,
+                      fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
+                      fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
+                      fdwQuality, fdwPitchAndFamily, lpszFace)) != NULL)
+       break;
+
+      /* If we fail, try some similar fonts often found on Windows. */
+
+      if (tries == 0)
+       {
+         if (g_strcasecmp (family, "helvetica") == 0)
+           lpszFace = "arial";
+         else if (g_strcasecmp (family, "new century schoolbook") == 0)
+           lpszFace = "century schoolbook";
+         else if (g_strcasecmp (family, "courier") == 0)
+           lpszFace = "courier new";
+         else if (g_strcasecmp (family, "lucida") == 0)
+           lpszFace = "lucida sans unicode";
+         else if (g_strcasecmp (family, "lucidatypewriter") == 0)
+           lpszFace = "lucida console";
+         else if (g_strcasecmp (family, "times") == 0)
+           lpszFace = "times new roman";
+       }
+      else if (tries == 1)
+       {
+         if (g_strcasecmp (family, "courier") == 0)
+           {
+             lpszFace = "";
+             fdwPitchAndFamily |= FF_MODERN;
+           }
+         else if (g_strcasecmp (family, "times new roman") == 0)
+           {
+             lpszFace = "";
+             fdwPitchAndFamily |= FF_ROMAN;
+           }
+         else if (g_strcasecmp (family, "helvetica") == 0
+                  || g_strcasecmp (family, "lucida") == 0)
+           {
+             lpszFace = "";
+             fdwPitchAndFamily |= FF_SWISS;
+           }
+         else
+           {
+             lpszFace = "";
+             fdwPitchAndFamily = (fdwPitchAndFamily & 0x0F) | FF_DONTCARE;
+           }
+       }
+      else
+       break;
+      tries++;
+    }
+  
+  if (!private->xfont)
+    {
+      g_warning ("gdk_font_load: font %s not found", font_name);
+      g_free (font);
+      return NULL;
+    }
+      
+  private->ref_count = 1;
+  font->type = GDK_FONT_FONT;
+  GetObject (private->xfont, sizeof (logfont), &logfont);
+  oldfont = SelectObject (gdk_DC, private->xfont);
+  GetTextMetrics (gdk_DC, &textmetric);
+  SelectObject (gdk_DC, oldfont);
+  font->ascent = textmetric.tmAscent;
+  font->descent = textmetric.tmDescent;
+
+  GDK_NOTE (MISC, g_print ("gdk_font_load: %s = %#x asc %d desc %d\n",
+                          font_name, private->xfont,
+                          font->ascent, font->descent));
+
+  /* This memory is leaked, so shoot me. */
+  f = g_new (HANDLE, 1);
+  *f = (HANDLE) ((guint) private->xfont + HFONT_DITHER);
+  gdk_xid_table_insert (f, font);
+
+  return font;
+}
+
+GdkFont*
+gdk_fontset_load (gchar *fontset_name)
+{
+  g_warning ("gdk_fontset_load: Not implemented");
+  return NULL;
+}
+
+GdkFont*
+gdk_font_ref (GdkFont *font)
+{
+  GdkFontPrivate *private;
+
+  g_return_val_if_fail (font != NULL, NULL);
+
+  private = (GdkFontPrivate*) font;
+  private->ref_count += 1;
+  return font;
+}
+
+void
+gdk_font_unref (GdkFont *font)
+{
+  GdkFontPrivate *private;
+
+  g_return_if_fail (font != NULL);
+
+  private = (GdkFontPrivate*) font;
+
+  private->ref_count -= 1;
+  if (private->ref_count == 0)
+    {
+      switch (font->type)
+       {
+       case GDK_FONT_FONT:
+         GDK_NOTE (MISC, g_print ("gdk_font_unref %#x\n", private->xfont));
+
+         gdk_xid_table_remove ((HANDLE) ((guint) private->xfont + HFONT_DITHER));
+         DeleteObject (private->xfont);
+         break;
+
+       default:
+         g_assert_not_reached ();
+       }
+      g_free (font);
+    }
+}
+
+gint
+gdk_font_id (const GdkFont *font)
+{
+  const GdkFontPrivate *font_private;
+
+  g_return_val_if_fail (font != NULL, 0);
+
+  font_private = (const GdkFontPrivate*) font;
+
+  if (font->type == GDK_FONT_FONT)
+    return (gint) font_private->xfont;
+
+  g_assert_not_reached ();
+  return 0;
+}
+
+gint
+gdk_font_equal (const GdkFont *fonta,
+                const GdkFont *fontb)
+{
+  const GdkFontPrivate *privatea;
+  const GdkFontPrivate *privateb;
+
+  g_return_val_if_fail (fonta != NULL, FALSE);
+  g_return_val_if_fail (fontb != NULL, FALSE);
+
+  privatea = (const GdkFontPrivate*) fonta;
+  privateb = (const GdkFontPrivate*) fontb;
+
+  if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
+    return (privatea->xfont == privateb->xfont);
+
+  g_assert_not_reached ();
+  return 0;
+}
+
+gint
+gdk_string_width (GdkFont     *font,
+                 const gchar *string)
+{
+  return gdk_text_width (font, string, strlen (string));
+}
+
+gint
+gdk_text_width (GdkFont      *font,
+               const gchar  *text,
+               gint          text_length)
+{
+  GdkFontPrivate *private;
+  HGDIOBJ oldfont;
+  SIZE size;
+  gint width;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      oldfont = SelectObject (gdk_DC, private->xfont);
+      GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
+      SelectObject (gdk_DC, oldfont);
+      width = size.cx;
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+  return width;
+}
+
+gint
+gdk_text_width_wc (GdkFont       *font,
+                  const GdkWChar *text,
+                  gint            text_length)
+{
+  GdkFontPrivate *private;
+  HGDIOBJ oldfont;
+  SIZE size;
+  wchar_t *wcstr;
+  gint i, width;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      wcstr = g_new (wchar_t, text_length);
+      for (i = 0; i < text_length; i++)
+       wcstr[i] = text[i];
+      oldfont = SelectObject (gdk_DC, private->xfont);
+      GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size);
+      g_free (wcstr);
+      SelectObject (gdk_DC, oldfont);
+      width = size.cx;
+      break;
+
+    default:
+      width = 0;
+    }
+  return width;
+}
+
+gint
+gdk_char_width (GdkFont *font,
+               gchar    character)
+{
+  return gdk_text_width (font, &character, 1);
+}
+
+gint
+gdk_char_width_wc (GdkFont *font,
+                  GdkWChar character)
+{
+  return gdk_text_width_wc (font, &character, 1);
+}
+
+gint
+gdk_string_measure (GdkFont     *font,
+                    const gchar *string)
+{
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (string != NULL, -1);
+
+  return gdk_text_measure (font, string, strlen (string));
+}
+
+void
+gdk_text_extents (GdkFont     *font,
+                  const gchar *text,
+                  gint         text_length,
+                 gint        *lbearing,
+                 gint        *rbearing,
+                 gint        *width,
+                 gint        *ascent,
+                 gint        *descent)
+{
+  GdkFontPrivate *private;
+  HGDIOBJ oldfont;
+  SIZE size;
+
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (text != NULL);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      oldfont = SelectObject (gdk_DC, private->xfont);
+      GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
+      SelectObject (gdk_DC, oldfont);
+      /* XXX This is all quite bogus */
+      if (lbearing)
+       *lbearing = 0;
+      if (rbearing)
+       *rbearing = 0;
+      if (width)
+       *width = size.cx;
+      if (ascent)
+       *ascent = size.cy + 1;
+      if (descent)
+       *descent = font->descent + 1;
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+void
+gdk_text_extents_wc (GdkFont        *font,
+                    const GdkWChar *text,
+                    gint            text_length,
+                    gint           *lbearing,
+                    gint           *rbearing,
+                    gint           *width,
+                    gint           *ascent,
+                    gint           *descent)
+{
+  GdkFontPrivate *private;
+  HGDIOBJ oldfont;
+  SIZE size;
+  wchar_t *wcstr;
+  gint i;
+
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (text != NULL);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      wcstr = g_new (wchar_t, text_length);
+      for (i = 0; i < text_length; i++)
+       wcstr[i] = text[i];
+      oldfont = SelectObject (gdk_DC, private->xfont);
+      GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size);
+      g_free (wcstr);
+      SelectObject (gdk_DC, oldfont);
+
+      /* XXX This is all quite bogus */
+      if (lbearing)
+       *lbearing = 0;
+      if (rbearing)
+       *rbearing = 0;
+      if (width)
+       *width = size.cx;
+      if (ascent)
+       *ascent = size.cy + 1;
+      if (descent)
+       *descent = font->descent + 1;
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+void
+gdk_string_extents (GdkFont     *font,
+                   const gchar *string,
+                   gint        *lbearing,
+                   gint        *rbearing,
+                   gint        *width,
+                   gint        *ascent,
+                   gint        *descent)
+{
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (string != NULL);
+
+  gdk_text_extents (font, string, strlen (string),
+                   lbearing, rbearing, width, ascent, descent);
+}
+
+
+gint
+gdk_text_measure (GdkFont     *font,
+                  const gchar *text,
+                  gint         text_length)
+{
+  GdkFontPrivate *private;
+  gint width;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      return gdk_text_width (font, text, text_length); /* ??? */
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+  return 0;
+}
+
+gint
+gdk_char_measure (GdkFont *font,
+                  gchar    character)
+{
+  g_return_val_if_fail (font != NULL, -1);
+
+  return gdk_text_measure (font, &character, 1);
+}
+
+gint
+gdk_string_height (GdkFont     *font,
+                  const gchar *string)
+{
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (string != NULL, -1);
+
+  return gdk_text_height (font, string, strlen (string));
+}
+
+gint
+gdk_text_height (GdkFont     *font,
+                const gchar *text,
+                gint         text_length)
+{
+  GdkFontPrivate *private;
+  HGDIOBJ oldfont;
+  SIZE size;
+  gint height;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      oldfont = SelectObject (gdk_DC, private->xfont);
+      GetTextExtentPoint32 (gdk_DC, text, text_length, &size);
+      SelectObject (gdk_DC, oldfont);
+      height = size.cy;
+      break;
+
+    default:
+      g_error ("font->type = %d", font->type);
+    }
+  return height;
+}
+
+gint
+gdk_char_height (GdkFont *font,
+                gchar    character)
+{
+  g_return_val_if_fail (font != NULL, -1);
+
+  return gdk_text_height (font, &character, 1);
+}
diff --git a/gdk/win32/gdkfont.c b/gdk/win32/gdkfont.c
new file mode 100644 (file)
index 0000000..cfe9382
--- /dev/null
@@ -0,0 +1,697 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "gdk.h"
+#include "gdkprivate.h"
+
+GdkFont*
+gdk_font_load (const gchar *font_name)
+{
+  GdkFont *font;
+  GdkFontPrivate *private;
+  LOGFONT logfont;
+  HGDIOBJ oldfont;
+  TEXTMETRIC textmetric;
+  HANDLE *f;
+  DWORD fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet,
+    fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily;
+  const char *lpszFace;
+
+  int numfields, n1, n2, tries;
+  char foundry[32], family[100], weight[32], slant[32], set_width[32],
+    spacing[32], registry[32], encoding[32];
+  char pixel_size[10], point_size[10], res_x[10], res_y[10], avg_width[10];
+  int c;
+  char *p;
+  int nHeight, nWidth, nEscapement, nOrientation, fnWeight;
+  int logpixelsy;
+
+  private = g_new (GdkFontPrivate, 1);
+  font = (GdkFont*) private;
+
+  numfields = sscanf (font_name,
+                     "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n",
+                     foundry,
+                     family,
+                     weight,
+                     slant,
+                     set_width,
+                     &n1);
+  if (numfields == 0)
+    {
+      /* Probably a plain Windows font name */
+      nHeight = 0;
+      nWidth = 0;
+      nEscapement = 0;
+      nOrientation = 0;
+      fnWeight = FW_DONTCARE;
+      fdwItalic = FALSE;
+      fdwUnderline = FALSE;
+      fdwStrikeOut = FALSE;
+      fdwCharSet = ANSI_CHARSET;
+      fdwOutputPrecision = OUT_TT_PRECIS;
+      fdwClipPrecision = CLIP_DEFAULT_PRECIS;
+      fdwQuality = PROOF_QUALITY;
+      fdwPitchAndFamily = DEFAULT_PITCH;
+      lpszFace = font_name;
+    }
+  else if (numfields != 5)
+    {
+      g_warning ("gdk_font_load: font name %s illegal", font_name);
+      g_free (font);
+      return NULL;
+    }
+  else
+    {
+      /* It must be a XLFD name */
+
+      /* Check for hex escapes in the font family,
+       * put in there by gtkfontsel.
+       */
+      p = family;
+      while (*p)
+       {
+         if (*p == '%' && isxdigit (p[1]) && isxdigit (p[2]))
+           {
+             sscanf (p+1, "%2x", &c);
+             *p = c;
+             strcpy (p+1, p+3);
+           }
+         p++;
+       }
+
+      /* Skip add_style which often is empty in the requested font name */
+      while (font_name[n1] && font_name[n1] != '-')
+       n1++;
+      numfields++;
+
+      numfields += sscanf (font_name + n1,
+                          "-%8[^-]-%8[^-]-%8[^-]-%8[^-]-%30[^-]-%8[^-]-%30[^-]-%30[^-]%n",
+                          pixel_size,
+                          point_size,
+                          res_x,
+                          res_y,
+                          spacing,
+                          avg_width,
+                          registry,
+                          encoding,
+                          &n2);
+
+      if (numfields != 14 || font_name[n1 + n2] != '\0')
+       {
+         g_warning ("gdk_font_load: font name %s illegal", font_name);
+         g_free (font);
+         return NULL;
+       }
+
+      logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY);
+
+      if (strcmp (pixel_size, "*") == 0)
+       if (strcmp (point_size, "*") == 0)
+         nHeight = 0;
+       else
+         nHeight = (int) (((double) atoi (point_size))/720.*logpixelsy);
+      else
+       nHeight = atoi (pixel_size);
+
+      nWidth = 0;
+      nEscapement = 0;
+      nOrientation = 0;
+
+      if (g_strcasecmp (weight, "thin") == 0)
+       fnWeight = FW_THIN;
+      else if (g_strcasecmp (weight, "extralight") == 0)
+       fnWeight = FW_EXTRALIGHT;
+      else if (g_strcasecmp (weight, "ultralight") == 0)
+       fnWeight = FW_ULTRALIGHT;
+      else if (g_strcasecmp (weight, "light") == 0)
+       fnWeight = FW_LIGHT;
+      else if (g_strcasecmp (weight, "normal") == 0)
+       fnWeight = FW_NORMAL;
+      else if (g_strcasecmp (weight, "regular") == 0)
+       fnWeight = FW_REGULAR;
+      else if (g_strcasecmp (weight, "medium") == 0)
+       fnWeight = FW_MEDIUM;
+      else if (g_strcasecmp (weight, "semibold") == 0)
+       fnWeight = FW_SEMIBOLD;
+      else if (g_strcasecmp (weight, "demibold") == 0)
+       fnWeight = FW_DEMIBOLD;
+      else if (g_strcasecmp (weight, "bold") == 0)
+       fnWeight = FW_BOLD;
+      else if (g_strcasecmp (weight, "extrabold") == 0)
+       fnWeight = FW_EXTRABOLD;
+      else if (g_strcasecmp (weight, "ultrabold") == 0)
+       fnWeight = FW_ULTRABOLD;
+      else if (g_strcasecmp (weight, "heavy") == 0)
+       fnWeight = FW_HEAVY;
+      else if (g_strcasecmp (weight, "black") == 0)
+       fnWeight = FW_BLACK;
+      else
+       fnWeight = FW_DONTCARE;
+
+      if (g_strcasecmp (slant, "italic") == 0
+         || g_strcasecmp (slant, "oblique") == 0
+         || g_strcasecmp (slant, "i") == 0
+         || g_strcasecmp (slant, "o") == 0)
+       fdwItalic = TRUE;
+      else
+       fdwItalic = FALSE;
+      fdwUnderline = FALSE;
+      fdwStrikeOut = FALSE;
+      if (g_strcasecmp (registry, "iso8859") == 0)
+       if (strcmp (encoding, "1") == 0)
+         fdwCharSet = ANSI_CHARSET;
+       else
+         fdwCharSet = ANSI_CHARSET; /* XXX ??? */
+      else if (g_strcasecmp (registry, "windows") == 0)
+       if (g_strcasecmp (encoding, "symbol") == 0)
+         fdwCharSet = SYMBOL_CHARSET;
+       else if (g_strcasecmp (encoding, "shiftjis") == 0)
+         fdwCharSet = SHIFTJIS_CHARSET;
+       else if (g_strcasecmp (encoding, "gb2312") == 0)
+         fdwCharSet = GB2312_CHARSET;
+       else if (g_strcasecmp (encoding, "hangeul") == 0)
+         fdwCharSet = HANGEUL_CHARSET;
+       else if (g_strcasecmp (encoding, "chinesebig5") == 0)
+         fdwCharSet = CHINESEBIG5_CHARSET;
+       else if (g_strcasecmp (encoding, "johab") == 0)
+         fdwCharSet = JOHAB_CHARSET;
+       else if (g_strcasecmp (encoding, "hebrew") == 0)
+         fdwCharSet = HEBREW_CHARSET;
+       else if (g_strcasecmp (encoding, "arabic") == 0)
+         fdwCharSet = ARABIC_CHARSET;
+       else if (g_strcasecmp (encoding, "greek") == 0)
+         fdwCharSet = GREEK_CHARSET;
+       else if (g_strcasecmp (encoding, "turkish") == 0)
+         fdwCharSet = TURKISH_CHARSET;
+       else if (g_strcasecmp (encoding, "easteurope") == 0)
+         fdwCharSet = EASTEUROPE_CHARSET;
+       else if (g_strcasecmp (encoding, "russian") == 0)
+         fdwCharSet = RUSSIAN_CHARSET;
+       else if (g_strcasecmp (encoding, "mac") == 0)
+         fdwCharSet = MAC_CHARSET;
+       else if (g_strcasecmp (encoding, "baltic") == 0)
+         fdwCharSet = BALTIC_CHARSET;
+       else
+         fdwCharSet = ANSI_CHARSET; /* XXX ??? */
+      else
+       fdwCharSet = ANSI_CHARSET; /* XXX ??? */
+      fdwOutputPrecision = OUT_TT_PRECIS;
+      fdwClipPrecision = CLIP_DEFAULT_PRECIS;
+      fdwQuality = PROOF_QUALITY;
+      if (g_strcasecmp (spacing, "m") == 0)
+       fdwPitchAndFamily = FIXED_PITCH;
+      else if (g_strcasecmp (spacing, "p") == 0)
+       fdwPitchAndFamily = VARIABLE_PITCH;
+      else 
+       fdwPitchAndFamily = DEFAULT_PITCH;
+      lpszFace = family;
+    }
+
+  for (tries = 0; ; tries++)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_font_load: trying CreateFont(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%#.02x,\"%s\")\n",
+                              nHeight, nWidth, nEscapement, nOrientation,
+                              fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
+                              fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
+                              fdwQuality, fdwPitchAndFamily, lpszFace));
+      if ((private->xfont =
+          CreateFont (nHeight, nWidth, nEscapement, nOrientation,
+                      fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
+                      fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
+                      fdwQuality, fdwPitchAndFamily, lpszFace)) != NULL)
+       break;
+
+      /* If we fail, try some similar fonts often found on Windows. */
+
+      if (tries == 0)
+       {
+         if (g_strcasecmp (family, "helvetica") == 0)
+           lpszFace = "arial";
+         else if (g_strcasecmp (family, "new century schoolbook") == 0)
+           lpszFace = "century schoolbook";
+         else if (g_strcasecmp (family, "courier") == 0)
+           lpszFace = "courier new";
+         else if (g_strcasecmp (family, "lucida") == 0)
+           lpszFace = "lucida sans unicode";
+         else if (g_strcasecmp (family, "lucidatypewriter") == 0)
+           lpszFace = "lucida console";
+         else if (g_strcasecmp (family, "times") == 0)
+           lpszFace = "times new roman";
+       }
+      else if (tries == 1)
+       {
+         if (g_strcasecmp (family, "courier") == 0)
+           {
+             lpszFace = "";
+             fdwPitchAndFamily |= FF_MODERN;
+           }
+         else if (g_strcasecmp (family, "times new roman") == 0)
+           {
+             lpszFace = "";
+             fdwPitchAndFamily |= FF_ROMAN;
+           }
+         else if (g_strcasecmp (family, "helvetica") == 0
+                  || g_strcasecmp (family, "lucida") == 0)
+           {
+             lpszFace = "";
+             fdwPitchAndFamily |= FF_SWISS;
+           }
+         else
+           {
+             lpszFace = "";
+             fdwPitchAndFamily = (fdwPitchAndFamily & 0x0F) | FF_DONTCARE;
+           }
+       }
+      else
+       break;
+      tries++;
+    }
+  
+  if (!private->xfont)
+    {
+      g_warning ("gdk_font_load: font %s not found", font_name);
+      g_free (font);
+      return NULL;
+    }
+      
+  private->ref_count = 1;
+  font->type = GDK_FONT_FONT;
+  GetObject (private->xfont, sizeof (logfont), &logfont);
+  oldfont = SelectObject (gdk_DC, private->xfont);
+  GetTextMetrics (gdk_DC, &textmetric);
+  SelectObject (gdk_DC, oldfont);
+  font->ascent = textmetric.tmAscent;
+  font->descent = textmetric.tmDescent;
+
+  GDK_NOTE (MISC, g_print ("gdk_font_load: %s = %#x asc %d desc %d\n",
+                          font_name, private->xfont,
+                          font->ascent, font->descent));
+
+  /* This memory is leaked, so shoot me. */
+  f = g_new (HANDLE, 1);
+  *f = (HANDLE) ((guint) private->xfont + HFONT_DITHER);
+  gdk_xid_table_insert (f, font);
+
+  return font;
+}
+
+GdkFont*
+gdk_fontset_load (gchar *fontset_name)
+{
+  g_warning ("gdk_fontset_load: Not implemented");
+  return NULL;
+}
+
+GdkFont*
+gdk_font_ref (GdkFont *font)
+{
+  GdkFontPrivate *private;
+
+  g_return_val_if_fail (font != NULL, NULL);
+
+  private = (GdkFontPrivate*) font;
+  private->ref_count += 1;
+  return font;
+}
+
+void
+gdk_font_unref (GdkFont *font)
+{
+  GdkFontPrivate *private;
+
+  g_return_if_fail (font != NULL);
+
+  private = (GdkFontPrivate*) font;
+
+  private->ref_count -= 1;
+  if (private->ref_count == 0)
+    {
+      switch (font->type)
+       {
+       case GDK_FONT_FONT:
+         GDK_NOTE (MISC, g_print ("gdk_font_unref %#x\n", private->xfont));
+
+         gdk_xid_table_remove ((HANDLE) ((guint) private->xfont + HFONT_DITHER));
+         DeleteObject (private->xfont);
+         break;
+
+       default:
+         g_assert_not_reached ();
+       }
+      g_free (font);
+    }
+}
+
+gint
+gdk_font_id (const GdkFont *font)
+{
+  const GdkFontPrivate *font_private;
+
+  g_return_val_if_fail (font != NULL, 0);
+
+  font_private = (const GdkFontPrivate*) font;
+
+  if (font->type == GDK_FONT_FONT)
+    return (gint) font_private->xfont;
+
+  g_assert_not_reached ();
+  return 0;
+}
+
+gint
+gdk_font_equal (const GdkFont *fonta,
+                const GdkFont *fontb)
+{
+  const GdkFontPrivate *privatea;
+  const GdkFontPrivate *privateb;
+
+  g_return_val_if_fail (fonta != NULL, FALSE);
+  g_return_val_if_fail (fontb != NULL, FALSE);
+
+  privatea = (const GdkFontPrivate*) fonta;
+  privateb = (const GdkFontPrivate*) fontb;
+
+  if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
+    return (privatea->xfont == privateb->xfont);
+
+  g_assert_not_reached ();
+  return 0;
+}
+
+gint
+gdk_string_width (GdkFont     *font,
+                 const gchar *string)
+{
+  return gdk_text_width (font, string, strlen (string));
+}
+
+gint
+gdk_text_width (GdkFont      *font,
+               const gchar  *text,
+               gint          text_length)
+{
+  GdkFontPrivate *private;
+  HGDIOBJ oldfont;
+  SIZE size;
+  gint width;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      oldfont = SelectObject (gdk_DC, private->xfont);
+      GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
+      SelectObject (gdk_DC, oldfont);
+      width = size.cx;
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+  return width;
+}
+
+gint
+gdk_text_width_wc (GdkFont       *font,
+                  const GdkWChar *text,
+                  gint            text_length)
+{
+  GdkFontPrivate *private;
+  HGDIOBJ oldfont;
+  SIZE size;
+  wchar_t *wcstr;
+  gint i, width;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      wcstr = g_new (wchar_t, text_length);
+      for (i = 0; i < text_length; i++)
+       wcstr[i] = text[i];
+      oldfont = SelectObject (gdk_DC, private->xfont);
+      GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size);
+      g_free (wcstr);
+      SelectObject (gdk_DC, oldfont);
+      width = size.cx;
+      break;
+
+    default:
+      width = 0;
+    }
+  return width;
+}
+
+gint
+gdk_char_width (GdkFont *font,
+               gchar    character)
+{
+  return gdk_text_width (font, &character, 1);
+}
+
+gint
+gdk_char_width_wc (GdkFont *font,
+                  GdkWChar character)
+{
+  return gdk_text_width_wc (font, &character, 1);
+}
+
+gint
+gdk_string_measure (GdkFont     *font,
+                    const gchar *string)
+{
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (string != NULL, -1);
+
+  return gdk_text_measure (font, string, strlen (string));
+}
+
+void
+gdk_text_extents (GdkFont     *font,
+                  const gchar *text,
+                  gint         text_length,
+                 gint        *lbearing,
+                 gint        *rbearing,
+                 gint        *width,
+                 gint        *ascent,
+                 gint        *descent)
+{
+  GdkFontPrivate *private;
+  HGDIOBJ oldfont;
+  SIZE size;
+
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (text != NULL);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      oldfont = SelectObject (gdk_DC, private->xfont);
+      GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
+      SelectObject (gdk_DC, oldfont);
+      /* XXX This is all quite bogus */
+      if (lbearing)
+       *lbearing = 0;
+      if (rbearing)
+       *rbearing = 0;
+      if (width)
+       *width = size.cx;
+      if (ascent)
+       *ascent = size.cy + 1;
+      if (descent)
+       *descent = font->descent + 1;
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+void
+gdk_text_extents_wc (GdkFont        *font,
+                    const GdkWChar *text,
+                    gint            text_length,
+                    gint           *lbearing,
+                    gint           *rbearing,
+                    gint           *width,
+                    gint           *ascent,
+                    gint           *descent)
+{
+  GdkFontPrivate *private;
+  HGDIOBJ oldfont;
+  SIZE size;
+  wchar_t *wcstr;
+  gint i;
+
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (text != NULL);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      wcstr = g_new (wchar_t, text_length);
+      for (i = 0; i < text_length; i++)
+       wcstr[i] = text[i];
+      oldfont = SelectObject (gdk_DC, private->xfont);
+      GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size);
+      g_free (wcstr);
+      SelectObject (gdk_DC, oldfont);
+
+      /* XXX This is all quite bogus */
+      if (lbearing)
+       *lbearing = 0;
+      if (rbearing)
+       *rbearing = 0;
+      if (width)
+       *width = size.cx;
+      if (ascent)
+       *ascent = size.cy + 1;
+      if (descent)
+       *descent = font->descent + 1;
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+void
+gdk_string_extents (GdkFont     *font,
+                   const gchar *string,
+                   gint        *lbearing,
+                   gint        *rbearing,
+                   gint        *width,
+                   gint        *ascent,
+                   gint        *descent)
+{
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (string != NULL);
+
+  gdk_text_extents (font, string, strlen (string),
+                   lbearing, rbearing, width, ascent, descent);
+}
+
+
+gint
+gdk_text_measure (GdkFont     *font,
+                  const gchar *text,
+                  gint         text_length)
+{
+  GdkFontPrivate *private;
+  gint width;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      return gdk_text_width (font, text, text_length); /* ??? */
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+  return 0;
+}
+
+gint
+gdk_char_measure (GdkFont *font,
+                  gchar    character)
+{
+  g_return_val_if_fail (font != NULL, -1);
+
+  return gdk_text_measure (font, &character, 1);
+}
+
+gint
+gdk_string_height (GdkFont     *font,
+                  const gchar *string)
+{
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (string != NULL, -1);
+
+  return gdk_text_height (font, string, strlen (string));
+}
+
+gint
+gdk_text_height (GdkFont     *font,
+                const gchar *text,
+                gint         text_length)
+{
+  GdkFontPrivate *private;
+  HGDIOBJ oldfont;
+  SIZE size;
+  gint height;
+
+  g_return_val_if_fail (font != NULL, -1);
+  g_return_val_if_fail (text != NULL, -1);
+
+  private = (GdkFontPrivate*) font;
+
+  switch (font->type)
+    {
+    case GDK_FONT_FONT:
+      oldfont = SelectObject (gdk_DC, private->xfont);
+      GetTextExtentPoint32 (gdk_DC, text, text_length, &size);
+      SelectObject (gdk_DC, oldfont);
+      height = size.cy;
+      break;
+
+    default:
+      g_error ("font->type = %d", font->type);
+    }
+  return height;
+}
+
+gint
+gdk_char_height (GdkFont *font,
+                gchar    character)
+{
+  g_return_val_if_fail (font != NULL, -1);
+
+  return gdk_text_height (font, &character, 1);
+}
diff --git a/gdk/win32/gdkgc-win32.c b/gdk/win32/gdkgc-win32.c
new file mode 100644 (file)
index 0000000..6697090
--- /dev/null
@@ -0,0 +1,1373 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include "gdk.h"
+#include "gdkprivate.h"
+
+GdkGC*
+gdk_gc_new (GdkWindow *window)
+{
+  return gdk_gc_new_with_values (window, NULL, 0);
+}
+
+GdkGC*
+gdk_gc_new_with_values (GdkWindow      *window,
+                       GdkGCValues     *values,
+                       GdkGCValuesMask  values_mask)
+{
+  GdkWindowPrivate *window_private;
+  GdkGC *gc;
+  GdkGCPrivate *private;
+  static GdkColor black;
+  static GdkColor white;
+  static gboolean beenhere = FALSE;
+
+  if (!beenhere)
+    {
+      gdk_color_black (gdk_colormap_get_system (), &black);
+      gdk_color_white (gdk_colormap_get_system (), &white);
+      beenhere = TRUE;
+    }
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  window_private = (GdkWindowPrivate*) window;
+  if (window_private->destroyed)
+    return NULL;
+
+  private = g_new (GdkGCPrivate, 1);
+  gc = (GdkGC*) private;
+
+  private->ref_count = 1;
+  private->rop2 = R2_COPYPEN;
+  private->fill_style = GDK_SOLID;
+  private->values_mask = values_mask;
+  private->values_mask |= GDK_GC_FUNCTION | GDK_GC_FILL;
+
+  GDK_NOTE (MISC, g_print ("gdk_gc_new: {"));
+
+  if (values_mask & GDK_GC_FOREGROUND)
+    {
+      private->foreground = values->foreground;
+    }
+  else
+    private->foreground = black;
+  
+  if (values_mask & GDK_GC_BACKGROUND)
+    {
+      private->background = values->background;
+    }
+  else
+    private->background = white;
+
+  if ((values_mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT))
+    {
+      private->font = (HFONT) ((GdkFontPrivate*) values->font)->xfont;
+      GDK_NOTE (MISC, g_print (" font=%#x", private->font));
+    }
+
+  if (values_mask & GDK_GC_FUNCTION)
+    {
+      switch (values->function)
+       {
+       case GDK_COPY:
+         private->rop2 = R2_COPYPEN; break;
+       case GDK_INVERT:
+         private->rop2 = R2_NOT; break;
+       case GDK_XOR:
+         private->rop2 = R2_XORPEN; break;
+       case GDK_CLEAR:
+         private->rop2 = R2_BLACK; break;
+       case GDK_AND:
+         private->rop2 = R2_MASKPEN; break;
+       case GDK_AND_REVERSE:
+         private->rop2 = R2_MASKPENNOT; break;
+       case GDK_AND_INVERT:
+         private->rop2 = R2_MASKNOTPEN; break;
+       case GDK_NOOP:
+         private->rop2 = R2_NOP; break;
+       case GDK_OR:
+         private->rop2 = R2_MERGEPEN; break;
+       case GDK_EQUIV:
+         private->rop2 = R2_NOTXORPEN; break;
+       case GDK_OR_REVERSE:
+         private->rop2 = R2_MERGEPENNOT; break;
+       case GDK_COPY_INVERT:
+         private->rop2 = R2_NOTCOPYPEN; break;
+       case GDK_OR_INVERT:
+         private->rop2 = R2_MERGENOTPEN; break;
+       case GDK_NAND:
+         private->rop2 = R2_NOTMASKPEN; break;
+       case GDK_SET:
+         private->rop2 = R2_WHITE; break;
+       }
+      GDK_NOTE (MISC, g_print (" function=%d", private->rop2));
+    }
+
+  if (values_mask & GDK_GC_FILL)
+    {
+      private->fill_style = values->fill;
+      GDK_NOTE (MISC, g_print (" fill=%d", private->fill_style));
+    }
+
+  if (values_mask & GDK_GC_TILE)
+    {
+      private->tile = values->tile;
+      gdk_pixmap_ref (private->tile);
+      GDK_NOTE (MISC, g_print (" tile=%#x", ((GdkPixmapPrivate *)private->tile)->xwindow));
+    }
+  else
+    private->tile = NULL;
+
+  if (values_mask & GDK_GC_STIPPLE)
+    {
+      private->stipple = values->tile;
+      gdk_pixmap_ref (private->stipple);
+      GDK_NOTE (MISC, g_print (" stipple=%#x", ((GdkPixmapPrivate *)private->stipple)->xwindow));
+    }
+  else
+    private->stipple = NULL;
+
+  if (values_mask & GDK_GC_CLIP_MASK)
+    {
+      private->clip_region =
+       BitmapToRegion (((GdkPixmapPrivate *)values->clip_mask)->xwindow);
+      GDK_NOTE (MISC, g_print (" clip=%#x", private->clip_region));
+    }
+  else
+    private->clip_region = NULL;
+
+  if (values_mask & GDK_GC_SUBWINDOW)
+    {
+      private->subwindow_mode = values->subwindow_mode;
+      GDK_NOTE (MISC, g_print (" subw=%d", private->subwindow_mode));
+    }
+
+  if (values_mask & GDK_GC_TS_X_ORIGIN)
+    {
+      private->ts_x_origin = values->ts_x_origin;
+      GDK_NOTE (MISC, g_print (" ts_x=%d", private->ts_x_origin));
+    }
+
+  if (values_mask & GDK_GC_TS_Y_ORIGIN)
+    {
+      private->ts_y_origin = values->ts_y_origin;
+      GDK_NOTE (MISC, g_print (" ts_y=%d", private->ts_y_origin));
+    }
+
+  if (values_mask & GDK_GC_CLIP_X_ORIGIN)
+    {
+      private->clip_x_origin = values->clip_x_origin;
+      GDK_NOTE (MISC, g_print (" clip_x=%d", private->clip_x_origin));
+    }
+
+  if (values_mask & GDK_GC_CLIP_Y_ORIGIN)
+    {
+      private->clip_y_origin = values->clip_y_origin; 
+      GDK_NOTE (MISC, g_print (" clip_y=%d", private->clip_y_origin));
+   }
+  if (values_mask & GDK_GC_EXPOSURES)
+    {
+      private->graphics_exposures = values->graphics_exposures;
+      GDK_NOTE (MISC, g_print (" exp=%d", private->graphics_exposures));
+    }
+
+  private->pen_style = PS_GEOMETRIC;
+  private->pen_width = 1;
+
+  if (values_mask & (GDK_GC_LINE_WIDTH | GDK_GC_LINE_STYLE))
+    {
+      if (values_mask & GDK_GC_LINE_WIDTH)
+       {
+         private->pen_width = values->line_width;
+         GDK_NOTE (MISC, g_print (" pw=%d", private->pen_width));
+       }
+      if (values_mask & GDK_GC_LINE_STYLE)
+       {
+         switch (values->line_style)
+           {
+           case GDK_LINE_SOLID:
+             private->pen_style |= PS_SOLID; break;
+           case GDK_LINE_ON_OFF_DASH:
+           case GDK_LINE_DOUBLE_DASH: /* ??? */
+             private->pen_style |= PS_DASH; break;
+           }
+         GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style));
+       }
+    }
+
+  if (values_mask & GDK_GC_CAP_STYLE)
+    {
+      switch (values->cap_style)
+       {
+       case GDK_CAP_NOT_LAST:  /* ??? */
+       case GDK_CAP_BUTT:
+         private->pen_style |= PS_ENDCAP_FLAT; break;
+       case GDK_CAP_ROUND:
+         private->pen_style |= PS_ENDCAP_ROUND; break;
+       case GDK_CAP_PROJECTING:
+         private->pen_style |= PS_ENDCAP_SQUARE; break;
+       }
+      GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style));
+    }
+
+  if (values_mask & GDK_GC_JOIN_STYLE)
+    {
+      switch (values->join_style)
+       {
+       case GDK_JOIN_MITER:
+         private->pen_style |= PS_JOIN_MITER;
+         break;
+       case GDK_JOIN_ROUND:
+         private->pen_style |= PS_JOIN_ROUND;
+         break;
+       case GDK_JOIN_BEVEL:
+         private->pen_style |= PS_JOIN_BEVEL;
+         break;
+       }
+      GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style));
+    }
+
+  private->hwnd = NULL;
+  private->xgc = NULL;
+
+  GDK_NOTE (MISC, g_print ("} = %p\n", private));
+
+  return gc;
+}
+
+void
+gdk_gc_destroy (GdkGC *gc)
+{
+  gdk_gc_unref (gc);
+}
+
+GdkGC *
+gdk_gc_ref (GdkGC *gc)
+{
+  GdkGCPrivate *private = (GdkGCPrivate*) gc;
+
+  g_return_val_if_fail (gc != NULL, NULL);
+  private->ref_count += 1;
+
+  return gc;
+}
+
+void
+gdk_gc_unref (GdkGC *gc)
+{
+  GdkGCPrivate *private = (GdkGCPrivate*) gc;
+  
+  g_return_if_fail (gc != NULL);
+  
+  if (private->ref_count > 1)
+    private->ref_count -= 1;
+  else
+    {
+      if (private->values_mask & GDK_GC_FONT)
+       {
+#if 0
+         if (!DeleteObject (private->font))
+           g_warning ("gdk_gc_unref: DeleteObject #3 failed");
+#endif
+       }
+
+      if (private->values_mask & GDK_GC_TILE)
+       {
+         gdk_pixmap_unref (private->tile);
+       }
+      
+      if (private->values_mask & GDK_GC_STIPPLE)
+       {
+         gdk_pixmap_unref (private->stipple);
+       }
+      
+      if (private->values_mask & GDK_GC_CLIP_MASK)
+       {
+         DeleteObject (private->clip_region);
+       }
+      memset (gc, 0, sizeof (GdkGCPrivate));
+      g_free (gc);
+    }
+}
+
+void
+gdk_gc_get_values (GdkGC       *gc,
+                  GdkGCValues *values)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (values != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  values->foreground = private->foreground;
+  values->background = private->background;
+  values->font = gdk_font_lookup (private->font);
+
+  switch (private->rop2)
+    {
+    case R2_COPYPEN:
+      values->function = GDK_COPY; break;
+    case R2_NOT:
+      values->function = GDK_INVERT; break;
+    case R2_XORPEN:
+      values->function = GDK_XOR; break;
+    case R2_BLACK:
+      values->function = GDK_CLEAR; break;
+    case R2_MASKPEN:
+      values->function = GDK_AND; break;
+    case R2_MASKPENNOT:
+      values->function = GDK_AND_REVERSE; break;
+    case R2_MASKNOTPEN:
+      values->function = GDK_AND_INVERT; break;
+    case R2_NOP:
+      values->function = GDK_NOOP; break;
+    case R2_MERGEPEN:
+      values->function = GDK_OR; break;
+    case R2_NOTXORPEN:
+      values->function = GDK_EQUIV; break;
+    case R2_MERGEPENNOT:
+      values->function = GDK_OR_REVERSE; break;
+    case R2_NOTCOPYPEN:
+      values->function = GDK_COPY_INVERT; break;
+    case R2_MERGENOTPEN:
+      values->function = GDK_OR_INVERT; break;
+    case R2_NOTMASKPEN:
+      values->function = GDK_NAND; break;
+    case R2_WHITE:
+      values->function = GDK_SET; break;
+    }
+
+  values->fill = private->fill_style;
+
+  values->tile = private->tile;
+  values->stipple = private->stipple;
+  if (private->clip_region != NULL)
+    {
+      RECT rect;
+      HBRUSH hbr;
+      HDC hdc;
+      HGDIOBJ oldbitmap;
+      GdkPixmap *pixmap;
+
+      GetRgnBox (private->clip_region, &rect);
+      pixmap =
+       gdk_pixmap_new (NULL, rect.right - rect.left, rect.bottom - rect.top,
+                       1);
+      hbr = GetStockObject (WHITE_BRUSH);
+      if ((hdc = CreateCompatibleDC (NULL)) == NULL)
+       g_warning ("gdk_gc_get_values: CreateCompatibleDC failed");
+      if ((oldbitmap =
+          SelectObject (hdc, ((GdkPixmapPrivate *) pixmap)->xwindow)) == NULL)
+       g_warning ("gdk_gc_get_values: SelectObject #1 failed");
+      hbr = GetStockObject (BLACK_BRUSH);
+      if (!FillRect (hdc, &rect, hbr))
+       g_warning ("gdk_gc_get_values: FillRect failed");
+      hbr = GetStockObject (WHITE_BRUSH);
+      if (!FillRgn (hdc, private->clip_region, hbr))
+       g_warning ("gdk_gc_get_values: FillRgn failed");
+      if (SelectObject (hdc, oldbitmap) == NULL)
+       g_warning ("gdk_gc_get_values: SelectObject #2 failed");
+      DeleteDC (hdc);
+      values->clip_mask = pixmap;
+    }
+  else
+    values->clip_mask = NULL;
+  values->subwindow_mode = private->subwindow_mode;
+  values->ts_x_origin = private->ts_x_origin;
+  values->ts_y_origin = private->ts_y_origin;
+  values->clip_x_origin = private->clip_x_origin;
+  values->clip_y_origin = private->clip_y_origin;
+  values->graphics_exposures = private->graphics_exposures;
+  values->line_width = private->pen_width;
+  
+  if (private->pen_style & PS_SOLID)
+    values->line_style = GDK_LINE_SOLID;
+  else if (private->pen_style & PS_DASH)
+    values->line_style = GDK_LINE_ON_OFF_DASH;
+  else
+    values->line_style = GDK_LINE_SOLID;
+
+  /* PS_ENDCAP_ROUND is zero */
+  if (private->pen_style & PS_ENDCAP_FLAT)
+    values->cap_style = GDK_CAP_BUTT;
+  else if (private->pen_style & PS_ENDCAP_SQUARE)
+    values->cap_style = GDK_CAP_PROJECTING;
+  else
+    values->cap_style = GDK_CAP_ROUND;
+    
+  /* PS_JOIN_ROUND is zero */
+  if (private->pen_style & PS_JOIN_MITER)
+    values->join_style = GDK_JOIN_MITER;
+  else if (private->pen_style & PS_JOIN_BEVEL)
+    values->join_style = GDK_JOIN_BEVEL;
+  else
+    values->join_style = GDK_JOIN_ROUND;
+}
+
+void
+gdk_gc_set_foreground (GdkGC   *gc,
+                      GdkColor *color)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (color != NULL);
+
+  private = (GdkGCPrivate*) gc;
+  {
+    GDK_NOTE (MISC, g_print ("gdk_gc_set_foreground: (%d) %s\n",
+                            private, gdk_color_to_string (color)));
+    private->foreground = *color;
+    private->values_mask |= GDK_GC_FOREGROUND;
+  }
+}
+
+void
+gdk_gc_set_background (GdkGC   *gc,
+                      GdkColor *color)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (color != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  GDK_NOTE (MISC, g_print ("gdk_gc_set_backround: (%d) %s\n",
+                          private, gdk_color_to_string(color)));
+  private->background = *color;
+  private->values_mask |= GDK_GC_BACKGROUND;
+}
+
+void
+gdk_gc_set_font (GdkGC  *gc,
+                GdkFont *font)
+{
+  GdkGCPrivate *gc_private;
+  GdkFontPrivate *font_private;
+
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (font != NULL);
+
+  if (font->type == GDK_FONT_FONT)
+    {
+      gc_private = (GdkGCPrivate*) gc;
+      font_private = (GdkFontPrivate*) font;
+      
+      GDK_NOTE (MISC, g_print ("gdk_gc_set_font: (%d) %#x\n",
+                              gc_private, font_private->xfont));
+
+      gc_private->font = font_private->xfont;
+      gc_private->values_mask |= GDK_GC_FONT;
+    }
+}
+
+void
+gdk_gc_set_function (GdkGC      *gc,
+                    GdkFunction  function)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  switch (function)
+    {
+    case GDK_COPY:
+      private->rop2 = R2_COPYPEN; break;
+    case GDK_INVERT:
+      private->rop2 = R2_NOT; break;
+    case GDK_XOR:
+      private->rop2 = R2_XORPEN; break;
+    case GDK_CLEAR:
+      private->rop2 = R2_BLACK; break;
+    case GDK_AND:
+      private->rop2 = R2_MASKPEN; break;
+    case GDK_AND_REVERSE:
+      private->rop2 = R2_MASKPENNOT; break;
+    case GDK_AND_INVERT:
+      private->rop2 = R2_MASKNOTPEN; break;
+    case GDK_NOOP:
+      private->rop2 = R2_NOP; break;
+    case GDK_OR:
+      private->rop2 = R2_MERGEPEN; break;
+    case GDK_EQUIV:
+      private->rop2 = R2_NOTXORPEN; break;
+    case GDK_OR_REVERSE:
+      private->rop2 = R2_MERGEPENNOT; break;
+    case GDK_COPY_INVERT:
+      private->rop2 = R2_NOTCOPYPEN; break;
+    case GDK_OR_INVERT:
+      private->rop2 = R2_MERGENOTPEN; break;
+    case GDK_NAND:
+      private->rop2 = R2_NOTMASKPEN; break;
+    case GDK_SET:
+      private->rop2 = R2_WHITE; break;
+    }
+  private->values_mask |= GDK_GC_FUNCTION;
+}
+
+void
+gdk_gc_set_fill (GdkGC  *gc,
+                GdkFill  fill)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  private->fill_style = fill;
+  private->values_mask |= GDK_GC_FILL;
+}
+
+void
+gdk_gc_set_tile (GdkGC    *gc,
+                GdkPixmap *tile)
+{
+  GdkGCPrivate *private;
+  GdkPixmapPrivate *pixmap_private;
+  HBITMAP pixmap;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  pixmap = NULL;
+
+  if (tile)
+    {
+      pixmap_private = (GdkPixmapPrivate*) tile;
+      pixmap = pixmap_private->xwindow;
+    }
+
+  if (private->tile != NULL)
+    gdk_pixmap_unref (private->tile);
+  private->tile = tile;
+  if (tile)
+    gdk_pixmap_ref (tile);
+  if (pixmap != NULL)
+    private->values_mask |= GDK_GC_TILE;
+  else
+    private->values_mask &= ~GDK_GC_TILE;
+}
+
+void
+gdk_gc_set_stipple (GdkGC     *gc,
+                   GdkPixmap *stipple)
+{
+  GdkGCPrivate *private;
+  GdkPixmapPrivate *pixmap_private;
+  HBITMAP pixmap;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  pixmap = NULL;
+
+  if (stipple)
+    {
+      pixmap_private = (GdkPixmapPrivate*) stipple;
+      pixmap = pixmap_private->xwindow;
+    }
+
+  if (private->stipple != NULL)
+    gdk_pixmap_unref (private->stipple);
+  private->stipple = stipple;
+  if (stipple)
+    gdk_pixmap_ref (stipple);
+  if (pixmap != NULL)
+    private->values_mask |= GDK_GC_STIPPLE;
+  else
+    private->values_mask &= ~GDK_GC_STIPPLE;
+}
+
+void
+gdk_gc_set_ts_origin (GdkGC *gc,
+                     gint   x,
+                     gint   y)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  private->ts_x_origin = x;
+  private->ts_y_origin = y;
+  private->values_mask |= GDK_GC_TS_X_ORIGIN |GDK_GC_TS_Y_ORIGIN;
+}
+
+void
+gdk_gc_set_clip_origin (GdkGC *gc,
+                       gint   x,
+                       gint   y)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_origin: (%d) +%d+%d\n",
+                          private, x, y));
+
+  private->clip_x_origin = x;
+  private->clip_y_origin = y;
+  private->values_mask |= GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN;
+}
+
+void
+gdk_gc_set_clip_mask (GdkGC    *gc,
+                     GdkBitmap *mask)
+{
+  GdkGCPrivate *private;
+  HBITMAP xmask;
+  
+  g_return_if_fail (gc != NULL);
+  
+  if (mask)
+    {
+      GdkWindowPrivate *mask_private;
+      
+      mask_private = (GdkWindowPrivate*) mask;
+      if (mask_private->destroyed)
+       return;
+      xmask = mask_private->xwindow;
+    }
+  else
+    xmask = NULL;
+
+  private = (GdkGCPrivate*) gc;
+
+  GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_mask: (%d) %#x\n", private, xmask));
+
+  if (private->clip_region != NULL)
+    if (!DeleteObject (private->clip_region))
+      g_warning ("gdk_gc_set_clip_mask: DeleteObject failed");
+  if (xmask != NULL)
+    {
+      private->clip_region = BitmapToRegion (xmask);
+      {
+       RECT rect;
+       GetRgnBox (private->clip_region, &rect);
+       GDK_NOTE (MISC, g_print ("...box = %dx%d@+%d+%d\n",
+                                rect.right - rect.left, rect.bottom - rect.top,
+                                rect.left, rect.top));
+      }
+#if 0
+      /* Test code that sets clip region to whole of mask */
+      {
+       BITMAP bm;
+       GetObject (xmask, sizeof (bm), &bm);
+       private->clip_region = CreateRectRgn (0, 0, bm.bmWidth, bm.bmHeight);
+      }
+#endif
+      private->values_mask |= GDK_GC_CLIP_MASK;
+    }
+  else
+    {
+      private->values_mask &= ~GDK_GC_CLIP_MASK;
+      private->clip_region = NULL;
+    }
+}
+
+void
+gdk_gc_set_clip_rectangle (GdkGC       *gc,
+                          GdkRectangle *rectangle)
+{
+  GdkGCPrivate *private;
+   
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  if (private->clip_region != NULL)
+    if (!DeleteObject (private->clip_region))
+      g_warning ("gdk_gc_set_clip_rectangle: DeleteObject failed");
+  if (rectangle)
+    {
+      GDK_NOTE (MISC,
+               g_print ("gdk_gc_set_clip_rectangle: (%d) %dx%d@+%d+%d\n",
+                        private,
+                        rectangle->width, rectangle->height,
+                        rectangle->x, rectangle->y));
+      if ((private->clip_region =
+          CreateRectRgn (rectangle->x, rectangle->y,
+                         rectangle->x + rectangle->width,
+                         rectangle->y + rectangle->height)) == NULL)
+       g_warning ("gdk_gc_set_clip_rectangle: CreateRectRgn failed");
+
+      private->values_mask |= GDK_GC_CLIP_MASK;
+    }
+  else
+    {
+      GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_rectangle: (%d) None\n",
+                              private));
+      private->clip_region = NULL;
+      private->values_mask &= ~GDK_GC_CLIP_MASK;
+    }
+    private->values_mask &= ~(GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN);
+} 
+
+void
+gdk_gc_set_clip_region (GdkGC           *gc,
+                       GdkRegion        *region)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_region: (%d) %s\n",
+                          private, (region != NULL ? "xxx" : "None")));
+
+  if (private->clip_region != NULL)
+    if (!DeleteObject (private->clip_region))
+      g_warning ("gdk_gc_set_clip_region: DeleteObject failed");
+  if (region)
+    {
+      GdkRegionPrivate *region_private;
+
+      region_private = (GdkRegionPrivate*) region;
+      private->clip_region = CreateRectRgn (1, 1, 0, 0);
+      CombineRgn (private->clip_region, region_private->xregion, NULL, RGN_COPY);
+      private->values_mask |= GDK_GC_CLIP_MASK;
+    }
+  else
+    {
+      private->clip_region = NULL;
+      private->values_mask &= ~GDK_GC_CLIP_MASK;
+    }
+}
+
+void
+gdk_gc_set_subwindow (GdkGC           *gc,
+                     GdkSubwindowMode  mode)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  private->subwindow_mode = mode;
+  private->values_mask |= GDK_GC_SUBWINDOW;
+}
+
+void
+gdk_gc_set_exposures (GdkGC *gc,
+                     gint   exposures)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  private->graphics_exposures = exposures;
+  private->values_mask |= GDK_GC_EXPOSURES;;
+}
+
+void
+gdk_gc_set_line_attributes (GdkGC      *gc,
+                           gint         line_width,
+                           GdkLineStyle line_style,
+                           GdkCapStyle  cap_style,
+                           GdkJoinStyle join_style)
+{
+  GdkGCPrivate *private;
+  int xline_style;
+  int xcap_style;
+  int xjoin_style;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  GDK_NOTE (MISC,
+           g_print ("gdk_gc_set_line_attributes: (%d) %d %s %s %s\n",
+                    private, line_width,
+                    (line_style == GDK_LINE_SOLID ? "SOLID" :
+                     (line_style == GDK_LINE_ON_OFF_DASH ? "ON_OFF_DASH" :
+                      (line_style == GDK_LINE_DOUBLE_DASH ? "DOUBLE_DASH" :
+                       "???"))),
+                    (cap_style == GDK_CAP_BUTT ? "BUTT" :
+                     (cap_style == GDK_CAP_ROUND ? "ROUND" :
+                      (cap_style == GDK_CAP_PROJECTING ? "PROJECTING" :
+                       "???"))),
+                    (join_style == GDK_JOIN_MITER ? "MITER" :
+                     (join_style == GDK_JOIN_ROUND ? "ROUND" :
+                      (join_style == GDK_JOIN_BEVEL ? "BEVEL" :
+                       "???")))));
+
+  private->pen_width = line_width;
+
+  /* Mask old style bits away */
+  private->pen_style &= ~(PS_STYLE_MASK|PS_ENDCAP_MASK|PS_JOIN_MASK);
+
+  /* Add new bits */
+  switch (line_style)
+    {
+    case GDK_LINE_SOLID:
+      private->pen_style |= PS_SOLID; break;
+    case GDK_LINE_ON_OFF_DASH:
+    case GDK_LINE_DOUBLE_DASH: /* ??? */
+      private->pen_style |= PS_DASH; break;
+    }
+
+  switch (cap_style)
+    {
+    case GDK_CAP_NOT_LAST:
+      /* ??? */
+      break;
+    case GDK_CAP_BUTT:
+      private->pen_style |= PS_ENDCAP_FLAT; break;
+    case GDK_CAP_ROUND:
+      private->pen_style |= PS_ENDCAP_ROUND; break;
+    case GDK_CAP_PROJECTING:
+      private->pen_style |= PS_ENDCAP_SQUARE; break;
+    }
+
+  switch (join_style)
+    {
+    case GDK_JOIN_MITER:
+      private->pen_style |= PS_JOIN_MITER;
+      break;
+    case GDK_JOIN_ROUND:
+      private->pen_style |= PS_JOIN_ROUND;
+      break;
+    case GDK_JOIN_BEVEL:
+      private->pen_style |= PS_JOIN_BEVEL;
+      break;
+    }
+}
+
+void
+gdk_gc_set_dashes (GdkGC *gc,
+                  gint   dash_offset,
+                  gchar  dash_list[],
+                  gint   n)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (dash_list != NULL);
+
+  /* XXX ??? */
+  g_warning ("gdk_gc_set_dashes: Not implemented");
+}
+
+void
+gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc)
+{
+  GdkGCPrivate *dst_private, *src_private;
+
+  src_private = (GdkGCPrivate *) src_gc;
+  dst_private = (GdkGCPrivate *) dst_gc;
+
+  *dst_private = *src_private;
+}
+
+HDC
+gdk_gc_predraw (GdkWindowPrivate *window_private,
+               GdkGCPrivate     *gc_private)
+{
+  GdkColormapPrivate *colormap_private =
+    (GdkColormapPrivate *) window_private->colormap;
+  COLORREF bg;
+  COLORREF fg;
+  LOGBRUSH logbrush;
+  HPEN hpen;
+  HBRUSH hbr;
+
+  g_assert (gc_private->xgc == NULL);
+
+  if (window_private->window_type == GDK_WINDOW_PIXMAP)
+    {
+      if ((gc_private->xgc = CreateCompatibleDC (NULL)) == NULL)
+       g_warning ("gdk_gc_predraw: CreateCompatibleDC failed");
+
+      if ((gc_private->saved_dc = SaveDC (gc_private->xgc)) == 0)
+       g_warning ("gdk_gc_predraw: SaveDC #1 failed");
+      
+      if (SelectObject (gc_private->xgc, window_private->xwindow) == NULL)
+       g_warning ("gdk_gc_predraw: SelectObject #1 failed");
+    }
+  else
+    {
+      if ((gc_private->xgc = GetDC (window_private->xwindow)) == NULL)
+       g_warning ("gdk_gc_predraw: GetDC failed");
+      
+      if ((gc_private->saved_dc = SaveDC (gc_private->xgc)) == 0)
+       g_warning ("gdk_gc_predraw: SaveDC #2 failed");
+    }
+  
+  gc_private->hwnd = window_private->xwindow;
+  
+  if (colormap_private == NULL)
+    {
+      /* A 1 bit deep bitmap */
+      struct
+      {
+       WORD palVersion;
+       WORD palNumEntries;
+       PALETTEENTRY palPalEntry[2];
+      } logpal;
+      static HPALETTE hpal = NULL;
+
+      if (hpal == NULL)
+       {
+         /* Create a b&w palette */
+         logpal.palVersion = 0x300;
+         logpal.palNumEntries = 2;
+         logpal.palPalEntry[0].peRed = 
+           logpal.palPalEntry[0].peGreen = 
+           logpal.palPalEntry[0].peBlue = 0x00;
+         logpal.palPalEntry[0].peFlags = 0x00;
+         logpal.palPalEntry[1].peRed = 
+           logpal.palPalEntry[1].peGreen = 
+           logpal.palPalEntry[1].peBlue = 0xFF;
+         logpal.palPalEntry[1].peFlags = 0x00;
+         if ((hpal = CreatePalette ((LOGPALETTE *) &logpal)) == NULL)
+           g_warning ("gdk_gc_predraw: CreatePalette failed");
+       }
+      SelectPalette (gc_private->xgc, hpal, FALSE);
+      RealizePalette (gc_private->xgc);
+      fg = PALETTEINDEX (gc_private->foreground.pixel);
+    }
+  else if (colormap_private != NULL
+          && colormap_private->xcolormap->rc_palette)
+    {
+      int k;
+      if (SelectPalette (gc_private->xgc,
+                        colormap_private->xcolormap->palette, FALSE) == NULL)
+       g_warning ("gdk_gc_predraw: SelectPalette failed");
+      if (TRUE || colormap_private->xcolormap->stale)
+       {
+         if ((k = RealizePalette (gc_private->xgc)) == GDI_ERROR)
+           g_warning ("gdk_gc_predraw: RealizePalette failed");
+         colormap_private->xcolormap->stale = FALSE;
+       }
+#if 0
+      g_print ("Selected palette %#x for gc %#x, realized %d colors\n",
+              colormap_private->xcolormap->palette, gc_private->xgc, k);
+#endif
+      fg = PALETTEINDEX (gc_private->foreground.pixel);
+    }
+  else
+    {
+      COLORREF foreground = RGB (gc_private->foreground.red >> 8,
+                                gc_private->foreground.green >> 8,
+                                gc_private->foreground.blue >> 8);
+      fg = GetNearestColor (gc_private->xgc, foreground);
+    }
+  logbrush.lbStyle = BS_SOLID;
+  logbrush.lbColor = fg;
+  if ((hpen = ExtCreatePen (gc_private->pen_style, gc_private->pen_width,
+                           &logbrush, 0, NULL)) == NULL)
+    g_warning ("gdk_gc_predraw: CreatePen failed");
+  
+  if (SelectObject (gc_private->xgc, hpen) == NULL)
+    g_warning ("gdk_gc_predraw: SelectObject #2 failed");
+
+  if (SetTextColor (gc_private->xgc, fg) == CLR_INVALID)
+    g_warning ("gdk_gc_predraw: SetTextColor failed");
+
+  if ((hbr = CreateSolidBrush (fg)) == NULL)
+    g_warning ("gdk_gc_predraw: CreateSolidBrush failed");
+
+  if (SelectObject (gc_private->xgc, hbr) == NULL)
+    g_warning ("gdk_gc_predraw: SelectObject #3 failed");
+
+  if (gc_private->values_mask & GDK_GC_BACKGROUND)
+    {
+      if (colormap_private == NULL)
+       {
+         /* a bitmap */
+         bg = PALETTEINDEX (gc_private->background.pixel);
+       }
+      else if (colormap_private != NULL
+         && colormap_private->xcolormap->rc_palette)
+       {
+         bg = PALETTEINDEX (gc_private->background.pixel);
+       }
+      else
+       {
+         COLORREF background = RGB (gc_private->background.red >> 8,
+                                    gc_private->background.green >> 8,
+                                    gc_private->background.blue >> 8);
+         bg = GetNearestColor (gc_private->xgc, background);
+       }
+      if (SetBkColor (gc_private->xgc, bg) == CLR_INVALID)
+       g_warning ("gdk_gc_predraw: SetBkColor failed");
+    }
+  
+  if (SetBkMode (gc_private->xgc, TRANSPARENT) == 0)
+    g_warning ("gdk_gc_predraw: SetBkMode failed");
+  
+  if (SetTextAlign (gc_private->xgc, TA_BASELINE) == GDI_ERROR)
+    g_warning ("gdk_gc_predraw: SetTextAlign failed");
+  
+  if (gc_private->values_mask & GDK_GC_FONT)
+    if (SelectObject (gc_private->xgc, gc_private->font) == NULL)
+      g_warning ("gdk_gc_predraw: SelectObject #4 failed");
+  
+  if (gc_private->values_mask & GDK_GC_FUNCTION)
+    if (SetROP2 (gc_private->xgc, gc_private->rop2) == 0)
+      g_warning ("gdk_gc_predraw: SetROP2 failed");
+
+  if (gc_private->values_mask & GDK_GC_CLIP_MASK
+      && gc_private->clip_region != NULL)
+    {
+      if (gc_private->values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
+       OffsetRgn (gc_private->clip_region,
+                  gc_private->clip_x_origin, gc_private->clip_y_origin);
+      SelectClipRgn (gc_private->xgc, gc_private->clip_region);
+    }
+
+  return gc_private->xgc;
+}
+
+void
+gdk_gc_postdraw (GdkWindowPrivate *window_private,
+                GdkGCPrivate     *gc_private)
+{
+  HGDIOBJ hpen;
+  HGDIOBJ hbr;
+  GdkColormapPrivate *colormap_private =
+    (GdkColormapPrivate *) window_private->colormap;
+
+  if ((hpen = GetCurrentObject (gc_private->xgc, OBJ_PEN)) == NULL)
+    g_warning ("gdk_gc_postdraw: GetCurrentObject #1 failed");
+
+  if ((hbr = GetCurrentObject (gc_private->xgc, OBJ_BRUSH)) == NULL)
+    g_warning ("gdk_gc_postdraw: GetCurrentObject #2 failed");
+
+  if (!RestoreDC (gc_private->xgc, gc_private->saved_dc))
+    g_warning ("gdk_gc_postdraw: RestoreDC failed");
+#if 0
+  if (colormap_private != NULL
+      && colormap_private->xcolormap->rc_palette
+      && colormap_private->xcolormap->stale)
+    {
+      SelectPalette (gc_private->xgc, GetStockObject (DEFAULT_PALETTE), FALSE);
+      if (!UnrealizeObject (colormap_private->xcolormap->palette))
+       g_warning ("gdk_gc_postraw: UnrealizeObject failed");
+    }
+#endif
+  if (window_private->window_type == GDK_WINDOW_PIXMAP)
+    {
+      if (!DeleteDC (gc_private->xgc))
+       g_warning ("gdk_gc_postdraw: DeleteDC failed");
+    }
+  else
+    {
+      ReleaseDC (gc_private->hwnd, gc_private->xgc);
+    }
+
+  if (hpen != NULL)
+    if (!DeleteObject (hpen))
+      g_warning ("gdk_gc_postdraw: DeleteObject #1 failed");
+  
+  if (hbr != NULL)
+    if (!DeleteObject (hbr))
+      g_warning ("gdk_gc_postdraw: DeleteObject #2 failed");
+
+  gc_private->xgc = NULL;
+}
+
+/* This function originally from Jean-Edouard Lachand-Robert, and
+ * available at www.codeguru.com. Simplified for our needs, now
+ * handles just one-bit deep bitmaps (in Window parlance, ie those
+ * that GDK calls bitmaps (and not pixmaps), with zero pixels being
+ * transparent.
+ */
+
+/*
+ *  BitmapToRegion :  Create a region from the "non-transparent" pixels of
+ *  a bitmap
+ *  Author :      Jean-Edouard Lachand-Robert
+ *  (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998.
+ */
+
+HRGN
+BitmapToRegion (HBITMAP hBmp)
+{
+  HRGN hRgn = NULL;
+  HDC hMemDC;
+  BITMAP bm;
+
+  struct
+  {
+    BITMAPINFOHEADER bmiHeader;
+#if 1
+    WORD bmiColors[2];
+#else
+    RGBQUAD bmiColors[2];
+#endif
+  } bmi;
+  VOID *pbits8; 
+  HBITMAP hbm8;
+  struct
+  {
+    WORD palVersion;
+    WORD palNumEntries;
+    PALETTEENTRY palPalEntry[2];
+  } logpal;
+  static HPALETTE bwPalette = NULL;
+
+  HBITMAP holdBmp;
+  HDC hDC;
+
+  BITMAP bm8;
+  HBITMAP holdBmp2;
+  DWORD maxRects;
+  RGNDATA *pData;
+  BYTE *p8;
+  int x, y;
+  HRGN h;
+
+  /* Create a B&W palette */
+  if (bwPalette == NULL)
+    {
+      /* Create a b&w palette */
+      logpal.palVersion = 0x300;
+      logpal.palNumEntries = 2;
+      logpal.palPalEntry[0].peRed = 
+       logpal.palPalEntry[0].peGreen = 
+       logpal.palPalEntry[0].peBlue = 0;
+      logpal.palPalEntry[0].peFlags = 0;
+      logpal.palPalEntry[1].peRed = 
+       logpal.palPalEntry[1].peGreen = 
+       logpal.palPalEntry[1].peBlue = 0xFF;
+      logpal.palPalEntry[1].peFlags = 0;
+      if ((bwPalette = CreatePalette ((LOGPALETTE *) &logpal)) == NULL)
+       g_warning ("BitmapToRegion: CreatePalette failed");
+    }
+
+  /* Create a memory DC inside which we will scan the bitmap content */
+  hMemDC = CreateCompatibleDC (NULL);
+  if (!hMemDC)
+    {
+      g_warning ("BitmapToRegion: CreateCompatibleDC #1 failed");
+      return NULL;
+    }
+
+  SelectPalette (hMemDC, bwPalette, FALSE);
+  RealizePalette (hMemDC);
+
+  /* Get bitmap size */
+  GetObject(hBmp, sizeof(bm), &bm);
+  
+  /* Create a 8 bits depth bitmap and select it into the memory DC */
+  bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+  bmi.bmiHeader.biWidth = bm.bmWidth;
+  bmi.bmiHeader.biHeight = bm.bmHeight;
+  bmi.bmiHeader.biPlanes = 1;
+  bmi.bmiHeader.biBitCount = 8;
+  bmi.bmiHeader.biCompression = BI_RGB;
+  bmi.bmiHeader.biSizeImage = 0;
+  bmi.bmiHeader.biXPelsPerMeter = 0;
+  bmi.bmiHeader.biYPelsPerMeter = 0;
+  bmi.bmiHeader.biClrUsed = 2;
+  bmi.bmiHeader.biClrImportant = 2;
+#if 1
+  bmi.bmiColors[0] = 0;
+  bmi.bmiColors[1] = 1;
+  hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi,
+                           DIB_PAL_COLORS, &pbits8, NULL, 0);
+#else
+  bmi.bmiColors[0].rgbBlue =
+    bmi.bmiColors[0].rgbGreen =
+    bmi.bmiColors[0].rgbRed = 0x00;
+  bmi.bmiColors[0].rgbReserved = 0x00;
+
+  bmi.bmiColors[1].rgbBlue =
+    bmi.bmiColors[1].rgbGreen =
+    bmi.bmiColors[1].rgbRed = 0xFF;
+  bmi.bmiColors[0].rgbReserved = 0x00;
+
+  hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi,
+                           DIB_RGB_COLORS, &pbits8, NULL, 0);
+#endif
+  if (!hbm8)
+    {
+      g_warning ("BitmapToRegion: CreateDIBSection failed");
+      DeleteDC (hMemDC);
+      return NULL;
+    }
+
+  holdBmp = (HBITMAP) SelectObject (hMemDC, hbm8);
+
+  /* Create a DC just to copy the bitmap into the memory DC*/
+  hDC = CreateCompatibleDC (hMemDC);
+  if (!hDC)
+    {
+      g_warning ("BitmapToRegion: CreateCompatibleDC #2 failed");
+      SelectObject (hMemDC, holdBmp);
+      DeleteObject (hbm8);
+      DeleteDC (hMemDC);
+      return NULL;
+    }
+
+  /* Get how many bytes per row we have for the bitmap bits */
+  GetObject (hbm8, sizeof (bm8), &bm8);
+
+  /* Hans Breuer found a fix to the long-standing erroneous behaviour
+   * on NT 4.0: There seems to be a bug in Win NT 4.0 GDI: scanlines
+   * in bitmaps are dword aligned on both Win95 and NT. In the case of
+   * a bitmap with 22 bytes worth of width, GetObject above returns
+   * with bmWidth == 22. On Win95 bmWidthBytes == 24, as it should be,
+   * but on NT is it 22. We need to correct this here.
+   */
+  bm8.bmWidthBytes = (((bm8.bmWidthBytes-1)/4)+1)*4; /* dword aligned!! */
+
+  /* Copy the bitmap into the memory DC*/
+  holdBmp2 = (HBITMAP) SelectObject (hDC, hBmp);
+
+  if (!BitBlt (hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY))
+    {
+      g_warning ("BitmapToRegion: BitBlt failed");
+      SelectObject (hDC, holdBmp2);
+      SelectObject (hMemDC, holdBmp);
+      DeleteObject (hbm8);
+      DeleteDC (hMemDC);
+      return NULL;
+    }
+  SelectObject (hDC, holdBmp2);
+  DeleteDC (hDC);
+
+  /* For better performances, we will use the ExtCreateRegion()
+   * function to create the region. This function take a RGNDATA
+   * structure on entry. We will add rectangles by amount of
+   * ALLOC_UNIT number in this structure.
+   */
+  #define ALLOC_UNIT  100
+  maxRects = ALLOC_UNIT;
+
+  pData = g_malloc (sizeof (RGNDATAHEADER) + (sizeof (RECT) * maxRects));
+  pData->rdh.dwSize = sizeof (RGNDATAHEADER);
+  pData->rdh.iType = RDH_RECTANGLES;
+  pData->rdh.nCount = pData->rdh.nRgnSize = 0;
+  SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
+
+  /* Scan each bitmap from bottom to top (the bitmap is inverted vertically)*/
+  p8 = (BYTE *) pbits8 + (bm8.bmHeight - 1) * bm8.bmWidthBytes;
+  for (y = 0; y < bm.bmHeight; y++)
+    {
+      /* Scan each bitmap row from left to right*/
+      for (x = 0; x < bm.bmWidth; x++)
+       {
+         /* Search for a continuous range of "non transparent pixels"*/
+         int x0 = x;
+         BYTE *p = p8 + x;
+         while (x < bm.bmWidth)
+           {
+             if (*p == 0)
+               /* This pixel is "transparent"*/
+               break;
+             p++;
+             x++;
+           }
+         
+         if (x > x0)
+           {
+             RECT *pr;
+             /* Add the pixels (x0, y) to (x, y+1) as a new rectangle
+              * in the region
+              */
+             if (pData->rdh.nCount >= maxRects)
+               {
+                 maxRects += ALLOC_UNIT;
+                 pData = g_realloc (pData, sizeof(RGNDATAHEADER)
+                                    + (sizeof(RECT) * maxRects));
+               }
+             pr = (RECT *) &pData->Buffer;
+             SetRect (&pr[pData->rdh.nCount], x0, y, x, y+1);
+             if (x0 < pData->rdh.rcBound.left)
+               pData->rdh.rcBound.left = x0;
+             if (y < pData->rdh.rcBound.top)
+               pData->rdh.rcBound.top = y;
+             if (x > pData->rdh.rcBound.right)
+               pData->rdh.rcBound.right = x;
+             if (y+1 > pData->rdh.rcBound.bottom)
+               pData->rdh.rcBound.bottom = y+1;
+             pData->rdh.nCount++;
+             
+             /* On Windows98, ExtCreateRegion() may fail if the
+              * number of rectangles is too large (ie: >
+              * 4000). Therefore, we have to create the region by
+              * multiple steps.
+              */
+             if (pData->rdh.nCount == 2000)
+               {
+                 HRGN h = ExtCreateRegion (NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
+                 if (hRgn)
+                   {
+                     CombineRgn(hRgn, hRgn, h, RGN_OR);
+                     DeleteObject(h);
+                   }
+                 else
+                   hRgn = h;
+                 pData->rdh.nCount = 0;
+                 SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
+               }
+           }
+       }
+      
+      /* Go to next row (remember, the bitmap is inverted vertically)*/
+      p8 -= bm8.bmWidthBytes;
+    }
+  
+  /* Create or extend the region with the remaining rectangles*/
+  h = ExtCreateRegion (NULL, sizeof (RGNDATAHEADER)
+                      + (sizeof (RECT) * maxRects), pData);
+  if (hRgn)
+    {
+      CombineRgn (hRgn, hRgn, h, RGN_OR);
+      DeleteObject (h);
+    }
+  else
+    hRgn = h;
+
+  /* Clean up*/
+  SelectObject(hMemDC, holdBmp);
+  DeleteObject (hbm8);
+  DeleteDC (hMemDC);
+
+  return hRgn;
+}
diff --git a/gdk/win32/gdkgc.c b/gdk/win32/gdkgc.c
new file mode 100644 (file)
index 0000000..6697090
--- /dev/null
@@ -0,0 +1,1373 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include "gdk.h"
+#include "gdkprivate.h"
+
+GdkGC*
+gdk_gc_new (GdkWindow *window)
+{
+  return gdk_gc_new_with_values (window, NULL, 0);
+}
+
+GdkGC*
+gdk_gc_new_with_values (GdkWindow      *window,
+                       GdkGCValues     *values,
+                       GdkGCValuesMask  values_mask)
+{
+  GdkWindowPrivate *window_private;
+  GdkGC *gc;
+  GdkGCPrivate *private;
+  static GdkColor black;
+  static GdkColor white;
+  static gboolean beenhere = FALSE;
+
+  if (!beenhere)
+    {
+      gdk_color_black (gdk_colormap_get_system (), &black);
+      gdk_color_white (gdk_colormap_get_system (), &white);
+      beenhere = TRUE;
+    }
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  window_private = (GdkWindowPrivate*) window;
+  if (window_private->destroyed)
+    return NULL;
+
+  private = g_new (GdkGCPrivate, 1);
+  gc = (GdkGC*) private;
+
+  private->ref_count = 1;
+  private->rop2 = R2_COPYPEN;
+  private->fill_style = GDK_SOLID;
+  private->values_mask = values_mask;
+  private->values_mask |= GDK_GC_FUNCTION | GDK_GC_FILL;
+
+  GDK_NOTE (MISC, g_print ("gdk_gc_new: {"));
+
+  if (values_mask & GDK_GC_FOREGROUND)
+    {
+      private->foreground = values->foreground;
+    }
+  else
+    private->foreground = black;
+  
+  if (values_mask & GDK_GC_BACKGROUND)
+    {
+      private->background = values->background;
+    }
+  else
+    private->background = white;
+
+  if ((values_mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT))
+    {
+      private->font = (HFONT) ((GdkFontPrivate*) values->font)->xfont;
+      GDK_NOTE (MISC, g_print (" font=%#x", private->font));
+    }
+
+  if (values_mask & GDK_GC_FUNCTION)
+    {
+      switch (values->function)
+       {
+       case GDK_COPY:
+         private->rop2 = R2_COPYPEN; break;
+       case GDK_INVERT:
+         private->rop2 = R2_NOT; break;
+       case GDK_XOR:
+         private->rop2 = R2_XORPEN; break;
+       case GDK_CLEAR:
+         private->rop2 = R2_BLACK; break;
+       case GDK_AND:
+         private->rop2 = R2_MASKPEN; break;
+       case GDK_AND_REVERSE:
+         private->rop2 = R2_MASKPENNOT; break;
+       case GDK_AND_INVERT:
+         private->rop2 = R2_MASKNOTPEN; break;
+       case GDK_NOOP:
+         private->rop2 = R2_NOP; break;
+       case GDK_OR:
+         private->rop2 = R2_MERGEPEN; break;
+       case GDK_EQUIV:
+         private->rop2 = R2_NOTXORPEN; break;
+       case GDK_OR_REVERSE:
+         private->rop2 = R2_MERGEPENNOT; break;
+       case GDK_COPY_INVERT:
+         private->rop2 = R2_NOTCOPYPEN; break;
+       case GDK_OR_INVERT:
+         private->rop2 = R2_MERGENOTPEN; break;
+       case GDK_NAND:
+         private->rop2 = R2_NOTMASKPEN; break;
+       case GDK_SET:
+         private->rop2 = R2_WHITE; break;
+       }
+      GDK_NOTE (MISC, g_print (" function=%d", private->rop2));
+    }
+
+  if (values_mask & GDK_GC_FILL)
+    {
+      private->fill_style = values->fill;
+      GDK_NOTE (MISC, g_print (" fill=%d", private->fill_style));
+    }
+
+  if (values_mask & GDK_GC_TILE)
+    {
+      private->tile = values->tile;
+      gdk_pixmap_ref (private->tile);
+      GDK_NOTE (MISC, g_print (" tile=%#x", ((GdkPixmapPrivate *)private->tile)->xwindow));
+    }
+  else
+    private->tile = NULL;
+
+  if (values_mask & GDK_GC_STIPPLE)
+    {
+      private->stipple = values->tile;
+      gdk_pixmap_ref (private->stipple);
+      GDK_NOTE (MISC, g_print (" stipple=%#x", ((GdkPixmapPrivate *)private->stipple)->xwindow));
+    }
+  else
+    private->stipple = NULL;
+
+  if (values_mask & GDK_GC_CLIP_MASK)
+    {
+      private->clip_region =
+       BitmapToRegion (((GdkPixmapPrivate *)values->clip_mask)->xwindow);
+      GDK_NOTE (MISC, g_print (" clip=%#x", private->clip_region));
+    }
+  else
+    private->clip_region = NULL;
+
+  if (values_mask & GDK_GC_SUBWINDOW)
+    {
+      private->subwindow_mode = values->subwindow_mode;
+      GDK_NOTE (MISC, g_print (" subw=%d", private->subwindow_mode));
+    }
+
+  if (values_mask & GDK_GC_TS_X_ORIGIN)
+    {
+      private->ts_x_origin = values->ts_x_origin;
+      GDK_NOTE (MISC, g_print (" ts_x=%d", private->ts_x_origin));
+    }
+
+  if (values_mask & GDK_GC_TS_Y_ORIGIN)
+    {
+      private->ts_y_origin = values->ts_y_origin;
+      GDK_NOTE (MISC, g_print (" ts_y=%d", private->ts_y_origin));
+    }
+
+  if (values_mask & GDK_GC_CLIP_X_ORIGIN)
+    {
+      private->clip_x_origin = values->clip_x_origin;
+      GDK_NOTE (MISC, g_print (" clip_x=%d", private->clip_x_origin));
+    }
+
+  if (values_mask & GDK_GC_CLIP_Y_ORIGIN)
+    {
+      private->clip_y_origin = values->clip_y_origin; 
+      GDK_NOTE (MISC, g_print (" clip_y=%d", private->clip_y_origin));
+   }
+  if (values_mask & GDK_GC_EXPOSURES)
+    {
+      private->graphics_exposures = values->graphics_exposures;
+      GDK_NOTE (MISC, g_print (" exp=%d", private->graphics_exposures));
+    }
+
+  private->pen_style = PS_GEOMETRIC;
+  private->pen_width = 1;
+
+  if (values_mask & (GDK_GC_LINE_WIDTH | GDK_GC_LINE_STYLE))
+    {
+      if (values_mask & GDK_GC_LINE_WIDTH)
+       {
+         private->pen_width = values->line_width;
+         GDK_NOTE (MISC, g_print (" pw=%d", private->pen_width));
+       }
+      if (values_mask & GDK_GC_LINE_STYLE)
+       {
+         switch (values->line_style)
+           {
+           case GDK_LINE_SOLID:
+             private->pen_style |= PS_SOLID; break;
+           case GDK_LINE_ON_OFF_DASH:
+           case GDK_LINE_DOUBLE_DASH: /* ??? */
+             private->pen_style |= PS_DASH; break;
+           }
+         GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style));
+       }
+    }
+
+  if (values_mask & GDK_GC_CAP_STYLE)
+    {
+      switch (values->cap_style)
+       {
+       case GDK_CAP_NOT_LAST:  /* ??? */
+       case GDK_CAP_BUTT:
+         private->pen_style |= PS_ENDCAP_FLAT; break;
+       case GDK_CAP_ROUND:
+         private->pen_style |= PS_ENDCAP_ROUND; break;
+       case GDK_CAP_PROJECTING:
+         private->pen_style |= PS_ENDCAP_SQUARE; break;
+       }
+      GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style));
+    }
+
+  if (values_mask & GDK_GC_JOIN_STYLE)
+    {
+      switch (values->join_style)
+       {
+       case GDK_JOIN_MITER:
+         private->pen_style |= PS_JOIN_MITER;
+         break;
+       case GDK_JOIN_ROUND:
+         private->pen_style |= PS_JOIN_ROUND;
+         break;
+       case GDK_JOIN_BEVEL:
+         private->pen_style |= PS_JOIN_BEVEL;
+         break;
+       }
+      GDK_NOTE (MISC, g_print (" ps=%#x", private->pen_style));
+    }
+
+  private->hwnd = NULL;
+  private->xgc = NULL;
+
+  GDK_NOTE (MISC, g_print ("} = %p\n", private));
+
+  return gc;
+}
+
+void
+gdk_gc_destroy (GdkGC *gc)
+{
+  gdk_gc_unref (gc);
+}
+
+GdkGC *
+gdk_gc_ref (GdkGC *gc)
+{
+  GdkGCPrivate *private = (GdkGCPrivate*) gc;
+
+  g_return_val_if_fail (gc != NULL, NULL);
+  private->ref_count += 1;
+
+  return gc;
+}
+
+void
+gdk_gc_unref (GdkGC *gc)
+{
+  GdkGCPrivate *private = (GdkGCPrivate*) gc;
+  
+  g_return_if_fail (gc != NULL);
+  
+  if (private->ref_count > 1)
+    private->ref_count -= 1;
+  else
+    {
+      if (private->values_mask & GDK_GC_FONT)
+       {
+#if 0
+         if (!DeleteObject (private->font))
+           g_warning ("gdk_gc_unref: DeleteObject #3 failed");
+#endif
+       }
+
+      if (private->values_mask & GDK_GC_TILE)
+       {
+         gdk_pixmap_unref (private->tile);
+       }
+      
+      if (private->values_mask & GDK_GC_STIPPLE)
+       {
+         gdk_pixmap_unref (private->stipple);
+       }
+      
+      if (private->values_mask & GDK_GC_CLIP_MASK)
+       {
+         DeleteObject (private->clip_region);
+       }
+      memset (gc, 0, sizeof (GdkGCPrivate));
+      g_free (gc);
+    }
+}
+
+void
+gdk_gc_get_values (GdkGC       *gc,
+                  GdkGCValues *values)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (values != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  values->foreground = private->foreground;
+  values->background = private->background;
+  values->font = gdk_font_lookup (private->font);
+
+  switch (private->rop2)
+    {
+    case R2_COPYPEN:
+      values->function = GDK_COPY; break;
+    case R2_NOT:
+      values->function = GDK_INVERT; break;
+    case R2_XORPEN:
+      values->function = GDK_XOR; break;
+    case R2_BLACK:
+      values->function = GDK_CLEAR; break;
+    case R2_MASKPEN:
+      values->function = GDK_AND; break;
+    case R2_MASKPENNOT:
+      values->function = GDK_AND_REVERSE; break;
+    case R2_MASKNOTPEN:
+      values->function = GDK_AND_INVERT; break;
+    case R2_NOP:
+      values->function = GDK_NOOP; break;
+    case R2_MERGEPEN:
+      values->function = GDK_OR; break;
+    case R2_NOTXORPEN:
+      values->function = GDK_EQUIV; break;
+    case R2_MERGEPENNOT:
+      values->function = GDK_OR_REVERSE; break;
+    case R2_NOTCOPYPEN:
+      values->function = GDK_COPY_INVERT; break;
+    case R2_MERGENOTPEN:
+      values->function = GDK_OR_INVERT; break;
+    case R2_NOTMASKPEN:
+      values->function = GDK_NAND; break;
+    case R2_WHITE:
+      values->function = GDK_SET; break;
+    }
+
+  values->fill = private->fill_style;
+
+  values->tile = private->tile;
+  values->stipple = private->stipple;
+  if (private->clip_region != NULL)
+    {
+      RECT rect;
+      HBRUSH hbr;
+      HDC hdc;
+      HGDIOBJ oldbitmap;
+      GdkPixmap *pixmap;
+
+      GetRgnBox (private->clip_region, &rect);
+      pixmap =
+       gdk_pixmap_new (NULL, rect.right - rect.left, rect.bottom - rect.top,
+                       1);
+      hbr = GetStockObject (WHITE_BRUSH);
+      if ((hdc = CreateCompatibleDC (NULL)) == NULL)
+       g_warning ("gdk_gc_get_values: CreateCompatibleDC failed");
+      if ((oldbitmap =
+          SelectObject (hdc, ((GdkPixmapPrivate *) pixmap)->xwindow)) == NULL)
+       g_warning ("gdk_gc_get_values: SelectObject #1 failed");
+      hbr = GetStockObject (BLACK_BRUSH);
+      if (!FillRect (hdc, &rect, hbr))
+       g_warning ("gdk_gc_get_values: FillRect failed");
+      hbr = GetStockObject (WHITE_BRUSH);
+      if (!FillRgn (hdc, private->clip_region, hbr))
+       g_warning ("gdk_gc_get_values: FillRgn failed");
+      if (SelectObject (hdc, oldbitmap) == NULL)
+       g_warning ("gdk_gc_get_values: SelectObject #2 failed");
+      DeleteDC (hdc);
+      values->clip_mask = pixmap;
+    }
+  else
+    values->clip_mask = NULL;
+  values->subwindow_mode = private->subwindow_mode;
+  values->ts_x_origin = private->ts_x_origin;
+  values->ts_y_origin = private->ts_y_origin;
+  values->clip_x_origin = private->clip_x_origin;
+  values->clip_y_origin = private->clip_y_origin;
+  values->graphics_exposures = private->graphics_exposures;
+  values->line_width = private->pen_width;
+  
+  if (private->pen_style & PS_SOLID)
+    values->line_style = GDK_LINE_SOLID;
+  else if (private->pen_style & PS_DASH)
+    values->line_style = GDK_LINE_ON_OFF_DASH;
+  else
+    values->line_style = GDK_LINE_SOLID;
+
+  /* PS_ENDCAP_ROUND is zero */
+  if (private->pen_style & PS_ENDCAP_FLAT)
+    values->cap_style = GDK_CAP_BUTT;
+  else if (private->pen_style & PS_ENDCAP_SQUARE)
+    values->cap_style = GDK_CAP_PROJECTING;
+  else
+    values->cap_style = GDK_CAP_ROUND;
+    
+  /* PS_JOIN_ROUND is zero */
+  if (private->pen_style & PS_JOIN_MITER)
+    values->join_style = GDK_JOIN_MITER;
+  else if (private->pen_style & PS_JOIN_BEVEL)
+    values->join_style = GDK_JOIN_BEVEL;
+  else
+    values->join_style = GDK_JOIN_ROUND;
+}
+
+void
+gdk_gc_set_foreground (GdkGC   *gc,
+                      GdkColor *color)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (color != NULL);
+
+  private = (GdkGCPrivate*) gc;
+  {
+    GDK_NOTE (MISC, g_print ("gdk_gc_set_foreground: (%d) %s\n",
+                            private, gdk_color_to_string (color)));
+    private->foreground = *color;
+    private->values_mask |= GDK_GC_FOREGROUND;
+  }
+}
+
+void
+gdk_gc_set_background (GdkGC   *gc,
+                      GdkColor *color)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (color != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  GDK_NOTE (MISC, g_print ("gdk_gc_set_backround: (%d) %s\n",
+                          private, gdk_color_to_string(color)));
+  private->background = *color;
+  private->values_mask |= GDK_GC_BACKGROUND;
+}
+
+void
+gdk_gc_set_font (GdkGC  *gc,
+                GdkFont *font)
+{
+  GdkGCPrivate *gc_private;
+  GdkFontPrivate *font_private;
+
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (font != NULL);
+
+  if (font->type == GDK_FONT_FONT)
+    {
+      gc_private = (GdkGCPrivate*) gc;
+      font_private = (GdkFontPrivate*) font;
+      
+      GDK_NOTE (MISC, g_print ("gdk_gc_set_font: (%d) %#x\n",
+                              gc_private, font_private->xfont));
+
+      gc_private->font = font_private->xfont;
+      gc_private->values_mask |= GDK_GC_FONT;
+    }
+}
+
+void
+gdk_gc_set_function (GdkGC      *gc,
+                    GdkFunction  function)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  switch (function)
+    {
+    case GDK_COPY:
+      private->rop2 = R2_COPYPEN; break;
+    case GDK_INVERT:
+      private->rop2 = R2_NOT; break;
+    case GDK_XOR:
+      private->rop2 = R2_XORPEN; break;
+    case GDK_CLEAR:
+      private->rop2 = R2_BLACK; break;
+    case GDK_AND:
+      private->rop2 = R2_MASKPEN; break;
+    case GDK_AND_REVERSE:
+      private->rop2 = R2_MASKPENNOT; break;
+    case GDK_AND_INVERT:
+      private->rop2 = R2_MASKNOTPEN; break;
+    case GDK_NOOP:
+      private->rop2 = R2_NOP; break;
+    case GDK_OR:
+      private->rop2 = R2_MERGEPEN; break;
+    case GDK_EQUIV:
+      private->rop2 = R2_NOTXORPEN; break;
+    case GDK_OR_REVERSE:
+      private->rop2 = R2_MERGEPENNOT; break;
+    case GDK_COPY_INVERT:
+      private->rop2 = R2_NOTCOPYPEN; break;
+    case GDK_OR_INVERT:
+      private->rop2 = R2_MERGENOTPEN; break;
+    case GDK_NAND:
+      private->rop2 = R2_NOTMASKPEN; break;
+    case GDK_SET:
+      private->rop2 = R2_WHITE; break;
+    }
+  private->values_mask |= GDK_GC_FUNCTION;
+}
+
+void
+gdk_gc_set_fill (GdkGC  *gc,
+                GdkFill  fill)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  private->fill_style = fill;
+  private->values_mask |= GDK_GC_FILL;
+}
+
+void
+gdk_gc_set_tile (GdkGC    *gc,
+                GdkPixmap *tile)
+{
+  GdkGCPrivate *private;
+  GdkPixmapPrivate *pixmap_private;
+  HBITMAP pixmap;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  pixmap = NULL;
+
+  if (tile)
+    {
+      pixmap_private = (GdkPixmapPrivate*) tile;
+      pixmap = pixmap_private->xwindow;
+    }
+
+  if (private->tile != NULL)
+    gdk_pixmap_unref (private->tile);
+  private->tile = tile;
+  if (tile)
+    gdk_pixmap_ref (tile);
+  if (pixmap != NULL)
+    private->values_mask |= GDK_GC_TILE;
+  else
+    private->values_mask &= ~GDK_GC_TILE;
+}
+
+void
+gdk_gc_set_stipple (GdkGC     *gc,
+                   GdkPixmap *stipple)
+{
+  GdkGCPrivate *private;
+  GdkPixmapPrivate *pixmap_private;
+  HBITMAP pixmap;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  pixmap = NULL;
+
+  if (stipple)
+    {
+      pixmap_private = (GdkPixmapPrivate*) stipple;
+      pixmap = pixmap_private->xwindow;
+    }
+
+  if (private->stipple != NULL)
+    gdk_pixmap_unref (private->stipple);
+  private->stipple = stipple;
+  if (stipple)
+    gdk_pixmap_ref (stipple);
+  if (pixmap != NULL)
+    private->values_mask |= GDK_GC_STIPPLE;
+  else
+    private->values_mask &= ~GDK_GC_STIPPLE;
+}
+
+void
+gdk_gc_set_ts_origin (GdkGC *gc,
+                     gint   x,
+                     gint   y)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  private->ts_x_origin = x;
+  private->ts_y_origin = y;
+  private->values_mask |= GDK_GC_TS_X_ORIGIN |GDK_GC_TS_Y_ORIGIN;
+}
+
+void
+gdk_gc_set_clip_origin (GdkGC *gc,
+                       gint   x,
+                       gint   y)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_origin: (%d) +%d+%d\n",
+                          private, x, y));
+
+  private->clip_x_origin = x;
+  private->clip_y_origin = y;
+  private->values_mask |= GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN;
+}
+
+void
+gdk_gc_set_clip_mask (GdkGC    *gc,
+                     GdkBitmap *mask)
+{
+  GdkGCPrivate *private;
+  HBITMAP xmask;
+  
+  g_return_if_fail (gc != NULL);
+  
+  if (mask)
+    {
+      GdkWindowPrivate *mask_private;
+      
+      mask_private = (GdkWindowPrivate*) mask;
+      if (mask_private->destroyed)
+       return;
+      xmask = mask_private->xwindow;
+    }
+  else
+    xmask = NULL;
+
+  private = (GdkGCPrivate*) gc;
+
+  GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_mask: (%d) %#x\n", private, xmask));
+
+  if (private->clip_region != NULL)
+    if (!DeleteObject (private->clip_region))
+      g_warning ("gdk_gc_set_clip_mask: DeleteObject failed");
+  if (xmask != NULL)
+    {
+      private->clip_region = BitmapToRegion (xmask);
+      {
+       RECT rect;
+       GetRgnBox (private->clip_region, &rect);
+       GDK_NOTE (MISC, g_print ("...box = %dx%d@+%d+%d\n",
+                                rect.right - rect.left, rect.bottom - rect.top,
+                                rect.left, rect.top));
+      }
+#if 0
+      /* Test code that sets clip region to whole of mask */
+      {
+       BITMAP bm;
+       GetObject (xmask, sizeof (bm), &bm);
+       private->clip_region = CreateRectRgn (0, 0, bm.bmWidth, bm.bmHeight);
+      }
+#endif
+      private->values_mask |= GDK_GC_CLIP_MASK;
+    }
+  else
+    {
+      private->values_mask &= ~GDK_GC_CLIP_MASK;
+      private->clip_region = NULL;
+    }
+}
+
+void
+gdk_gc_set_clip_rectangle (GdkGC       *gc,
+                          GdkRectangle *rectangle)
+{
+  GdkGCPrivate *private;
+   
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  if (private->clip_region != NULL)
+    if (!DeleteObject (private->clip_region))
+      g_warning ("gdk_gc_set_clip_rectangle: DeleteObject failed");
+  if (rectangle)
+    {
+      GDK_NOTE (MISC,
+               g_print ("gdk_gc_set_clip_rectangle: (%d) %dx%d@+%d+%d\n",
+                        private,
+                        rectangle->width, rectangle->height,
+                        rectangle->x, rectangle->y));
+      if ((private->clip_region =
+          CreateRectRgn (rectangle->x, rectangle->y,
+                         rectangle->x + rectangle->width,
+                         rectangle->y + rectangle->height)) == NULL)
+       g_warning ("gdk_gc_set_clip_rectangle: CreateRectRgn failed");
+
+      private->values_mask |= GDK_GC_CLIP_MASK;
+    }
+  else
+    {
+      GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_rectangle: (%d) None\n",
+                              private));
+      private->clip_region = NULL;
+      private->values_mask &= ~GDK_GC_CLIP_MASK;
+    }
+    private->values_mask &= ~(GDK_GC_CLIP_X_ORIGIN |GDK_GC_CLIP_Y_ORIGIN);
+} 
+
+void
+gdk_gc_set_clip_region (GdkGC           *gc,
+                       GdkRegion        *region)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  GDK_NOTE (MISC, g_print ("gdk_gc_set_clip_region: (%d) %s\n",
+                          private, (region != NULL ? "xxx" : "None")));
+
+  if (private->clip_region != NULL)
+    if (!DeleteObject (private->clip_region))
+      g_warning ("gdk_gc_set_clip_region: DeleteObject failed");
+  if (region)
+    {
+      GdkRegionPrivate *region_private;
+
+      region_private = (GdkRegionPrivate*) region;
+      private->clip_region = CreateRectRgn (1, 1, 0, 0);
+      CombineRgn (private->clip_region, region_private->xregion, NULL, RGN_COPY);
+      private->values_mask |= GDK_GC_CLIP_MASK;
+    }
+  else
+    {
+      private->clip_region = NULL;
+      private->values_mask &= ~GDK_GC_CLIP_MASK;
+    }
+}
+
+void
+gdk_gc_set_subwindow (GdkGC           *gc,
+                     GdkSubwindowMode  mode)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  private->subwindow_mode = mode;
+  private->values_mask |= GDK_GC_SUBWINDOW;
+}
+
+void
+gdk_gc_set_exposures (GdkGC *gc,
+                     gint   exposures)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  private->graphics_exposures = exposures;
+  private->values_mask |= GDK_GC_EXPOSURES;;
+}
+
+void
+gdk_gc_set_line_attributes (GdkGC      *gc,
+                           gint         line_width,
+                           GdkLineStyle line_style,
+                           GdkCapStyle  cap_style,
+                           GdkJoinStyle join_style)
+{
+  GdkGCPrivate *private;
+  int xline_style;
+  int xcap_style;
+  int xjoin_style;
+
+  g_return_if_fail (gc != NULL);
+
+  private = (GdkGCPrivate*) gc;
+
+  GDK_NOTE (MISC,
+           g_print ("gdk_gc_set_line_attributes: (%d) %d %s %s %s\n",
+                    private, line_width,
+                    (line_style == GDK_LINE_SOLID ? "SOLID" :
+                     (line_style == GDK_LINE_ON_OFF_DASH ? "ON_OFF_DASH" :
+                      (line_style == GDK_LINE_DOUBLE_DASH ? "DOUBLE_DASH" :
+                       "???"))),
+                    (cap_style == GDK_CAP_BUTT ? "BUTT" :
+                     (cap_style == GDK_CAP_ROUND ? "ROUND" :
+                      (cap_style == GDK_CAP_PROJECTING ? "PROJECTING" :
+                       "???"))),
+                    (join_style == GDK_JOIN_MITER ? "MITER" :
+                     (join_style == GDK_JOIN_ROUND ? "ROUND" :
+                      (join_style == GDK_JOIN_BEVEL ? "BEVEL" :
+                       "???")))));
+
+  private->pen_width = line_width;
+
+  /* Mask old style bits away */
+  private->pen_style &= ~(PS_STYLE_MASK|PS_ENDCAP_MASK|PS_JOIN_MASK);
+
+  /* Add new bits */
+  switch (line_style)
+    {
+    case GDK_LINE_SOLID:
+      private->pen_style |= PS_SOLID; break;
+    case GDK_LINE_ON_OFF_DASH:
+    case GDK_LINE_DOUBLE_DASH: /* ??? */
+      private->pen_style |= PS_DASH; break;
+    }
+
+  switch (cap_style)
+    {
+    case GDK_CAP_NOT_LAST:
+      /* ??? */
+      break;
+    case GDK_CAP_BUTT:
+      private->pen_style |= PS_ENDCAP_FLAT; break;
+    case GDK_CAP_ROUND:
+      private->pen_style |= PS_ENDCAP_ROUND; break;
+    case GDK_CAP_PROJECTING:
+      private->pen_style |= PS_ENDCAP_SQUARE; break;
+    }
+
+  switch (join_style)
+    {
+    case GDK_JOIN_MITER:
+      private->pen_style |= PS_JOIN_MITER;
+      break;
+    case GDK_JOIN_ROUND:
+      private->pen_style |= PS_JOIN_ROUND;
+      break;
+    case GDK_JOIN_BEVEL:
+      private->pen_style |= PS_JOIN_BEVEL;
+      break;
+    }
+}
+
+void
+gdk_gc_set_dashes (GdkGC *gc,
+                  gint   dash_offset,
+                  gchar  dash_list[],
+                  gint   n)
+{
+  GdkGCPrivate *private;
+
+  g_return_if_fail (gc != NULL);
+  g_return_if_fail (dash_list != NULL);
+
+  /* XXX ??? */
+  g_warning ("gdk_gc_set_dashes: Not implemented");
+}
+
+void
+gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc)
+{
+  GdkGCPrivate *dst_private, *src_private;
+
+  src_private = (GdkGCPrivate *) src_gc;
+  dst_private = (GdkGCPrivate *) dst_gc;
+
+  *dst_private = *src_private;
+}
+
+HDC
+gdk_gc_predraw (GdkWindowPrivate *window_private,
+               GdkGCPrivate     *gc_private)
+{
+  GdkColormapPrivate *colormap_private =
+    (GdkColormapPrivate *) window_private->colormap;
+  COLORREF bg;
+  COLORREF fg;
+  LOGBRUSH logbrush;
+  HPEN hpen;
+  HBRUSH hbr;
+
+  g_assert (gc_private->xgc == NULL);
+
+  if (window_private->window_type == GDK_WINDOW_PIXMAP)
+    {
+      if ((gc_private->xgc = CreateCompatibleDC (NULL)) == NULL)
+       g_warning ("gdk_gc_predraw: CreateCompatibleDC failed");
+
+      if ((gc_private->saved_dc = SaveDC (gc_private->xgc)) == 0)
+       g_warning ("gdk_gc_predraw: SaveDC #1 failed");
+      
+      if (SelectObject (gc_private->xgc, window_private->xwindow) == NULL)
+       g_warning ("gdk_gc_predraw: SelectObject #1 failed");
+    }
+  else
+    {
+      if ((gc_private->xgc = GetDC (window_private->xwindow)) == NULL)
+       g_warning ("gdk_gc_predraw: GetDC failed");
+      
+      if ((gc_private->saved_dc = SaveDC (gc_private->xgc)) == 0)
+       g_warning ("gdk_gc_predraw: SaveDC #2 failed");
+    }
+  
+  gc_private->hwnd = window_private->xwindow;
+  
+  if (colormap_private == NULL)
+    {
+      /* A 1 bit deep bitmap */
+      struct
+      {
+       WORD palVersion;
+       WORD palNumEntries;
+       PALETTEENTRY palPalEntry[2];
+      } logpal;
+      static HPALETTE hpal = NULL;
+
+      if (hpal == NULL)
+       {
+         /* Create a b&w palette */
+         logpal.palVersion = 0x300;
+         logpal.palNumEntries = 2;
+         logpal.palPalEntry[0].peRed = 
+           logpal.palPalEntry[0].peGreen = 
+           logpal.palPalEntry[0].peBlue = 0x00;
+         logpal.palPalEntry[0].peFlags = 0x00;
+         logpal.palPalEntry[1].peRed = 
+           logpal.palPalEntry[1].peGreen = 
+           logpal.palPalEntry[1].peBlue = 0xFF;
+         logpal.palPalEntry[1].peFlags = 0x00;
+         if ((hpal = CreatePalette ((LOGPALETTE *) &logpal)) == NULL)
+           g_warning ("gdk_gc_predraw: CreatePalette failed");
+       }
+      SelectPalette (gc_private->xgc, hpal, FALSE);
+      RealizePalette (gc_private->xgc);
+      fg = PALETTEINDEX (gc_private->foreground.pixel);
+    }
+  else if (colormap_private != NULL
+          && colormap_private->xcolormap->rc_palette)
+    {
+      int k;
+      if (SelectPalette (gc_private->xgc,
+                        colormap_private->xcolormap->palette, FALSE) == NULL)
+       g_warning ("gdk_gc_predraw: SelectPalette failed");
+      if (TRUE || colormap_private->xcolormap->stale)
+       {
+         if ((k = RealizePalette (gc_private->xgc)) == GDI_ERROR)
+           g_warning ("gdk_gc_predraw: RealizePalette failed");
+         colormap_private->xcolormap->stale = FALSE;
+       }
+#if 0
+      g_print ("Selected palette %#x for gc %#x, realized %d colors\n",
+              colormap_private->xcolormap->palette, gc_private->xgc, k);
+#endif
+      fg = PALETTEINDEX (gc_private->foreground.pixel);
+    }
+  else
+    {
+      COLORREF foreground = RGB (gc_private->foreground.red >> 8,
+                                gc_private->foreground.green >> 8,
+                                gc_private->foreground.blue >> 8);
+      fg = GetNearestColor (gc_private->xgc, foreground);
+    }
+  logbrush.lbStyle = BS_SOLID;
+  logbrush.lbColor = fg;
+  if ((hpen = ExtCreatePen (gc_private->pen_style, gc_private->pen_width,
+                           &logbrush, 0, NULL)) == NULL)
+    g_warning ("gdk_gc_predraw: CreatePen failed");
+  
+  if (SelectObject (gc_private->xgc, hpen) == NULL)
+    g_warning ("gdk_gc_predraw: SelectObject #2 failed");
+
+  if (SetTextColor (gc_private->xgc, fg) == CLR_INVALID)
+    g_warning ("gdk_gc_predraw: SetTextColor failed");
+
+  if ((hbr = CreateSolidBrush (fg)) == NULL)
+    g_warning ("gdk_gc_predraw: CreateSolidBrush failed");
+
+  if (SelectObject (gc_private->xgc, hbr) == NULL)
+    g_warning ("gdk_gc_predraw: SelectObject #3 failed");
+
+  if (gc_private->values_mask & GDK_GC_BACKGROUND)
+    {
+      if (colormap_private == NULL)
+       {
+         /* a bitmap */
+         bg = PALETTEINDEX (gc_private->background.pixel);
+       }
+      else if (colormap_private != NULL
+         && colormap_private->xcolormap->rc_palette)
+       {
+         bg = PALETTEINDEX (gc_private->background.pixel);
+       }
+      else
+       {
+         COLORREF background = RGB (gc_private->background.red >> 8,
+                                    gc_private->background.green >> 8,
+                                    gc_private->background.blue >> 8);
+         bg = GetNearestColor (gc_private->xgc, background);
+       }
+      if (SetBkColor (gc_private->xgc, bg) == CLR_INVALID)
+       g_warning ("gdk_gc_predraw: SetBkColor failed");
+    }
+  
+  if (SetBkMode (gc_private->xgc, TRANSPARENT) == 0)
+    g_warning ("gdk_gc_predraw: SetBkMode failed");
+  
+  if (SetTextAlign (gc_private->xgc, TA_BASELINE) == GDI_ERROR)
+    g_warning ("gdk_gc_predraw: SetTextAlign failed");
+  
+  if (gc_private->values_mask & GDK_GC_FONT)
+    if (SelectObject (gc_private->xgc, gc_private->font) == NULL)
+      g_warning ("gdk_gc_predraw: SelectObject #4 failed");
+  
+  if (gc_private->values_mask & GDK_GC_FUNCTION)
+    if (SetROP2 (gc_private->xgc, gc_private->rop2) == 0)
+      g_warning ("gdk_gc_predraw: SetROP2 failed");
+
+  if (gc_private->values_mask & GDK_GC_CLIP_MASK
+      && gc_private->clip_region != NULL)
+    {
+      if (gc_private->values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
+       OffsetRgn (gc_private->clip_region,
+                  gc_private->clip_x_origin, gc_private->clip_y_origin);
+      SelectClipRgn (gc_private->xgc, gc_private->clip_region);
+    }
+
+  return gc_private->xgc;
+}
+
+void
+gdk_gc_postdraw (GdkWindowPrivate *window_private,
+                GdkGCPrivate     *gc_private)
+{
+  HGDIOBJ hpen;
+  HGDIOBJ hbr;
+  GdkColormapPrivate *colormap_private =
+    (GdkColormapPrivate *) window_private->colormap;
+
+  if ((hpen = GetCurrentObject (gc_private->xgc, OBJ_PEN)) == NULL)
+    g_warning ("gdk_gc_postdraw: GetCurrentObject #1 failed");
+
+  if ((hbr = GetCurrentObject (gc_private->xgc, OBJ_BRUSH)) == NULL)
+    g_warning ("gdk_gc_postdraw: GetCurrentObject #2 failed");
+
+  if (!RestoreDC (gc_private->xgc, gc_private->saved_dc))
+    g_warning ("gdk_gc_postdraw: RestoreDC failed");
+#if 0
+  if (colormap_private != NULL
+      && colormap_private->xcolormap->rc_palette
+      && colormap_private->xcolormap->stale)
+    {
+      SelectPalette (gc_private->xgc, GetStockObject (DEFAULT_PALETTE), FALSE);
+      if (!UnrealizeObject (colormap_private->xcolormap->palette))
+       g_warning ("gdk_gc_postraw: UnrealizeObject failed");
+    }
+#endif
+  if (window_private->window_type == GDK_WINDOW_PIXMAP)
+    {
+      if (!DeleteDC (gc_private->xgc))
+       g_warning ("gdk_gc_postdraw: DeleteDC failed");
+    }
+  else
+    {
+      ReleaseDC (gc_private->hwnd, gc_private->xgc);
+    }
+
+  if (hpen != NULL)
+    if (!DeleteObject (hpen))
+      g_warning ("gdk_gc_postdraw: DeleteObject #1 failed");
+  
+  if (hbr != NULL)
+    if (!DeleteObject (hbr))
+      g_warning ("gdk_gc_postdraw: DeleteObject #2 failed");
+
+  gc_private->xgc = NULL;
+}
+
+/* This function originally from Jean-Edouard Lachand-Robert, and
+ * available at www.codeguru.com. Simplified for our needs, now
+ * handles just one-bit deep bitmaps (in Window parlance, ie those
+ * that GDK calls bitmaps (and not pixmaps), with zero pixels being
+ * transparent.
+ */
+
+/*
+ *  BitmapToRegion :  Create a region from the "non-transparent" pixels of
+ *  a bitmap
+ *  Author :      Jean-Edouard Lachand-Robert
+ *  (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998.
+ */
+
+HRGN
+BitmapToRegion (HBITMAP hBmp)
+{
+  HRGN hRgn = NULL;
+  HDC hMemDC;
+  BITMAP bm;
+
+  struct
+  {
+    BITMAPINFOHEADER bmiHeader;
+#if 1
+    WORD bmiColors[2];
+#else
+    RGBQUAD bmiColors[2];
+#endif
+  } bmi;
+  VOID *pbits8; 
+  HBITMAP hbm8;
+  struct
+  {
+    WORD palVersion;
+    WORD palNumEntries;
+    PALETTEENTRY palPalEntry[2];
+  } logpal;
+  static HPALETTE bwPalette = NULL;
+
+  HBITMAP holdBmp;
+  HDC hDC;
+
+  BITMAP bm8;
+  HBITMAP holdBmp2;
+  DWORD maxRects;
+  RGNDATA *pData;
+  BYTE *p8;
+  int x, y;
+  HRGN h;
+
+  /* Create a B&W palette */
+  if (bwPalette == NULL)
+    {
+      /* Create a b&w palette */
+      logpal.palVersion = 0x300;
+      logpal.palNumEntries = 2;
+      logpal.palPalEntry[0].peRed = 
+       logpal.palPalEntry[0].peGreen = 
+       logpal.palPalEntry[0].peBlue = 0;
+      logpal.palPalEntry[0].peFlags = 0;
+      logpal.palPalEntry[1].peRed = 
+       logpal.palPalEntry[1].peGreen = 
+       logpal.palPalEntry[1].peBlue = 0xFF;
+      logpal.palPalEntry[1].peFlags = 0;
+      if ((bwPalette = CreatePalette ((LOGPALETTE *) &logpal)) == NULL)
+       g_warning ("BitmapToRegion: CreatePalette failed");
+    }
+
+  /* Create a memory DC inside which we will scan the bitmap content */
+  hMemDC = CreateCompatibleDC (NULL);
+  if (!hMemDC)
+    {
+      g_warning ("BitmapToRegion: CreateCompatibleDC #1 failed");
+      return NULL;
+    }
+
+  SelectPalette (hMemDC, bwPalette, FALSE);
+  RealizePalette (hMemDC);
+
+  /* Get bitmap size */
+  GetObject(hBmp, sizeof(bm), &bm);
+  
+  /* Create a 8 bits depth bitmap and select it into the memory DC */
+  bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+  bmi.bmiHeader.biWidth = bm.bmWidth;
+  bmi.bmiHeader.biHeight = bm.bmHeight;
+  bmi.bmiHeader.biPlanes = 1;
+  bmi.bmiHeader.biBitCount = 8;
+  bmi.bmiHeader.biCompression = BI_RGB;
+  bmi.bmiHeader.biSizeImage = 0;
+  bmi.bmiHeader.biXPelsPerMeter = 0;
+  bmi.bmiHeader.biYPelsPerMeter = 0;
+  bmi.bmiHeader.biClrUsed = 2;
+  bmi.bmiHeader.biClrImportant = 2;
+#if 1
+  bmi.bmiColors[0] = 0;
+  bmi.bmiColors[1] = 1;
+  hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi,
+                           DIB_PAL_COLORS, &pbits8, NULL, 0);
+#else
+  bmi.bmiColors[0].rgbBlue =
+    bmi.bmiColors[0].rgbGreen =
+    bmi.bmiColors[0].rgbRed = 0x00;
+  bmi.bmiColors[0].rgbReserved = 0x00;
+
+  bmi.bmiColors[1].rgbBlue =
+    bmi.bmiColors[1].rgbGreen =
+    bmi.bmiColors[1].rgbRed = 0xFF;
+  bmi.bmiColors[0].rgbReserved = 0x00;
+
+  hbm8 = CreateDIBSection (hMemDC, (BITMAPINFO *)&bmi,
+                           DIB_RGB_COLORS, &pbits8, NULL, 0);
+#endif
+  if (!hbm8)
+    {
+      g_warning ("BitmapToRegion: CreateDIBSection failed");
+      DeleteDC (hMemDC);
+      return NULL;
+    }
+
+  holdBmp = (HBITMAP) SelectObject (hMemDC, hbm8);
+
+  /* Create a DC just to copy the bitmap into the memory DC*/
+  hDC = CreateCompatibleDC (hMemDC);
+  if (!hDC)
+    {
+      g_warning ("BitmapToRegion: CreateCompatibleDC #2 failed");
+      SelectObject (hMemDC, holdBmp);
+      DeleteObject (hbm8);
+      DeleteDC (hMemDC);
+      return NULL;
+    }
+
+  /* Get how many bytes per row we have for the bitmap bits */
+  GetObject (hbm8, sizeof (bm8), &bm8);
+
+  /* Hans Breuer found a fix to the long-standing erroneous behaviour
+   * on NT 4.0: There seems to be a bug in Win NT 4.0 GDI: scanlines
+   * in bitmaps are dword aligned on both Win95 and NT. In the case of
+   * a bitmap with 22 bytes worth of width, GetObject above returns
+   * with bmWidth == 22. On Win95 bmWidthBytes == 24, as it should be,
+   * but on NT is it 22. We need to correct this here.
+   */
+  bm8.bmWidthBytes = (((bm8.bmWidthBytes-1)/4)+1)*4; /* dword aligned!! */
+
+  /* Copy the bitmap into the memory DC*/
+  holdBmp2 = (HBITMAP) SelectObject (hDC, hBmp);
+
+  if (!BitBlt (hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY))
+    {
+      g_warning ("BitmapToRegion: BitBlt failed");
+      SelectObject (hDC, holdBmp2);
+      SelectObject (hMemDC, holdBmp);
+      DeleteObject (hbm8);
+      DeleteDC (hMemDC);
+      return NULL;
+    }
+  SelectObject (hDC, holdBmp2);
+  DeleteDC (hDC);
+
+  /* For better performances, we will use the ExtCreateRegion()
+   * function to create the region. This function take a RGNDATA
+   * structure on entry. We will add rectangles by amount of
+   * ALLOC_UNIT number in this structure.
+   */
+  #define ALLOC_UNIT  100
+  maxRects = ALLOC_UNIT;
+
+  pData = g_malloc (sizeof (RGNDATAHEADER) + (sizeof (RECT) * maxRects));
+  pData->rdh.dwSize = sizeof (RGNDATAHEADER);
+  pData->rdh.iType = RDH_RECTANGLES;
+  pData->rdh.nCount = pData->rdh.nRgnSize = 0;
+  SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
+
+  /* Scan each bitmap from bottom to top (the bitmap is inverted vertically)*/
+  p8 = (BYTE *) pbits8 + (bm8.bmHeight - 1) * bm8.bmWidthBytes;
+  for (y = 0; y < bm.bmHeight; y++)
+    {
+      /* Scan each bitmap row from left to right*/
+      for (x = 0; x < bm.bmWidth; x++)
+       {
+         /* Search for a continuous range of "non transparent pixels"*/
+         int x0 = x;
+         BYTE *p = p8 + x;
+         while (x < bm.bmWidth)
+           {
+             if (*p == 0)
+               /* This pixel is "transparent"*/
+               break;
+             p++;
+             x++;
+           }
+         
+         if (x > x0)
+           {
+             RECT *pr;
+             /* Add the pixels (x0, y) to (x, y+1) as a new rectangle
+              * in the region
+              */
+             if (pData->rdh.nCount >= maxRects)
+               {
+                 maxRects += ALLOC_UNIT;
+                 pData = g_realloc (pData, sizeof(RGNDATAHEADER)
+                                    + (sizeof(RECT) * maxRects));
+               }
+             pr = (RECT *) &pData->Buffer;
+             SetRect (&pr[pData->rdh.nCount], x0, y, x, y+1);
+             if (x0 < pData->rdh.rcBound.left)
+               pData->rdh.rcBound.left = x0;
+             if (y < pData->rdh.rcBound.top)
+               pData->rdh.rcBound.top = y;
+             if (x > pData->rdh.rcBound.right)
+               pData->rdh.rcBound.right = x;
+             if (y+1 > pData->rdh.rcBound.bottom)
+               pData->rdh.rcBound.bottom = y+1;
+             pData->rdh.nCount++;
+             
+             /* On Windows98, ExtCreateRegion() may fail if the
+              * number of rectangles is too large (ie: >
+              * 4000). Therefore, we have to create the region by
+              * multiple steps.
+              */
+             if (pData->rdh.nCount == 2000)
+               {
+                 HRGN h = ExtCreateRegion (NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
+                 if (hRgn)
+                   {
+                     CombineRgn(hRgn, hRgn, h, RGN_OR);
+                     DeleteObject(h);
+                   }
+                 else
+                   hRgn = h;
+                 pData->rdh.nCount = 0;
+                 SetRect (&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
+               }
+           }
+       }
+      
+      /* Go to next row (remember, the bitmap is inverted vertically)*/
+      p8 -= bm8.bmWidthBytes;
+    }
+  
+  /* Create or extend the region with the remaining rectangles*/
+  h = ExtCreateRegion (NULL, sizeof (RGNDATAHEADER)
+                      + (sizeof (RECT) * maxRects), pData);
+  if (hRgn)
+    {
+      CombineRgn (hRgn, hRgn, h, RGN_OR);
+      DeleteObject (h);
+    }
+  else
+    hRgn = h;
+
+  /* Clean up*/
+  SelectObject(hMemDC, holdBmp);
+  DeleteObject (hbm8);
+  DeleteDC (hMemDC);
+
+  return hRgn;
+}
diff --git a/gdk/win32/gdkglobals-win32.c b/gdk/win32/gdkglobals-win32.c
new file mode 100644 (file)
index 0000000..d89aa0b
--- /dev/null
@@ -0,0 +1,94 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#if !defined (X_DISPLAY_MISSING)
+#include <X11/Xlib.h>
+#endif
+#include "gdk.h"
+#include "gdkprivate.h"
+
+guint             gdk_debug_flags = 0;
+HWND              gdk_root_window;
+HWND              gdk_leader_window;
+GdkWindowPrivate  gdk_root_parent = { { NULL, }, NULL, };
+#if !defined(X_DISPLAY_MISSING)
+gchar            *gdk_display_name = NULL;
+gint              gdk_use_xshm = TRUE;
+Atom              gdk_wm_delete_window;
+Atom              gdk_wm_take_focus;
+Atom              gdk_wm_protocols;
+Atom              gdk_wm_window_protocols[2];
+GdkDndCursorInfo  gdk_dnd_cursorinfo = {None, None, NULL, NULL,
+                                       {0,0}, {0,0}, NULL};
+GdkDndGlobals     gdk_dnd = {None,None,None,
+                            None,None,None,
+                            None,
+                            &gdk_dnd_cursorinfo,
+                            NULL,
+                            0,
+                            FALSE, FALSE, FALSE,
+                            None,
+                            {0,0},
+                            {0,0}, {0,0},
+                            {0,0,0,0}, NULL, None, 0};
+#elif defined (WINDOWS_DISPLAY)
+
+HDC              gdk_DC;
+HINSTANCE        gdk_DLLInstance;
+HINSTANCE        gdk_ProgInstance;
+
+UINT             gdk_selection_notify_msg;
+UINT             gdk_selection_request_msg;
+UINT             gdk_selection_clear_msg;
+GdkAtom                  gdk_clipboard_atom;
+GdkAtom                  gdk_win32_dropfiles_atom;
+GdkAtom                  gdk_ole2_dnd_atom;
+
+#endif /* WINDOWS_DISPLAY */
+
+Atom              gdk_selection_property;
+gchar            *gdk_progclass = NULL;
+gint              gdk_error_code;
+gint              gdk_error_warnings = TRUE;
+gint              gdk_null_window_warnings = TRUE;
+GList            *gdk_default_filters = NULL;
+
+gboolean      gdk_xim_using;           /* using XIM Protocol if TRUE */
+GdkWindow    *gdk_xim_window;          /* currently using Widow */
+
+GdkWindowPrivate *gdk_xgrab_window = NULL;  /* Window that currently holds the
+                                            *  x pointer grab
+                                            */
+
+GMutex *gdk_threads_mutex = NULL;          /* Global GDK lock */
+
+#ifdef USE_XIM
+GdkICPrivate *gdk_xim_ic;              /* currently using IC */
+GdkWindow *gdk_xim_window;             /* currently using Window */
+#endif
diff --git a/gdk/win32/gdkglobals.c b/gdk/win32/gdkglobals.c
new file mode 100644 (file)
index 0000000..d89aa0b
--- /dev/null
@@ -0,0 +1,94 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#if !defined (X_DISPLAY_MISSING)
+#include <X11/Xlib.h>
+#endif
+#include "gdk.h"
+#include "gdkprivate.h"
+
+guint             gdk_debug_flags = 0;
+HWND              gdk_root_window;
+HWND              gdk_leader_window;
+GdkWindowPrivate  gdk_root_parent = { { NULL, }, NULL, };
+#if !defined(X_DISPLAY_MISSING)
+gchar            *gdk_display_name = NULL;
+gint              gdk_use_xshm = TRUE;
+Atom              gdk_wm_delete_window;
+Atom              gdk_wm_take_focus;
+Atom              gdk_wm_protocols;
+Atom              gdk_wm_window_protocols[2];
+GdkDndCursorInfo  gdk_dnd_cursorinfo = {None, None, NULL, NULL,
+                                       {0,0}, {0,0}, NULL};
+GdkDndGlobals     gdk_dnd = {None,None,None,
+                            None,None,None,
+                            None,
+                            &gdk_dnd_cursorinfo,
+                            NULL,
+                            0,
+                            FALSE, FALSE, FALSE,
+                            None,
+                            {0,0},
+                            {0,0}, {0,0},
+                            {0,0,0,0}, NULL, None, 0};
+#elif defined (WINDOWS_DISPLAY)
+
+HDC              gdk_DC;
+HINSTANCE        gdk_DLLInstance;
+HINSTANCE        gdk_ProgInstance;
+
+UINT             gdk_selection_notify_msg;
+UINT             gdk_selection_request_msg;
+UINT             gdk_selection_clear_msg;
+GdkAtom                  gdk_clipboard_atom;
+GdkAtom                  gdk_win32_dropfiles_atom;
+GdkAtom                  gdk_ole2_dnd_atom;
+
+#endif /* WINDOWS_DISPLAY */
+
+Atom              gdk_selection_property;
+gchar            *gdk_progclass = NULL;
+gint              gdk_error_code;
+gint              gdk_error_warnings = TRUE;
+gint              gdk_null_window_warnings = TRUE;
+GList            *gdk_default_filters = NULL;
+
+gboolean      gdk_xim_using;           /* using XIM Protocol if TRUE */
+GdkWindow    *gdk_xim_window;          /* currently using Widow */
+
+GdkWindowPrivate *gdk_xgrab_window = NULL;  /* Window that currently holds the
+                                            *  x pointer grab
+                                            */
+
+GMutex *gdk_threads_mutex = NULL;          /* Global GDK lock */
+
+#ifdef USE_XIM
+GdkICPrivate *gdk_xim_ic;              /* currently using IC */
+GdkWindow *gdk_xim_window;             /* currently using Window */
+#endif
diff --git a/gdk/win32/gdkim-win32.c b/gdk/win32/gdkim-win32.c
new file mode 100644 (file)
index 0000000..e3f6e09
--- /dev/null
@@ -0,0 +1,248 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#  if STDC_HEADERS
+#    include <string.h>
+#  endif
+#endif
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdki18n.h"
+#include "gdkx.h"
+
+/* If this variable is FALSE, it indicates that we should
+ * avoid trying to use multibyte conversion functions and
+ * assume everything is 1-byte per character
+ */
+static gboolean gdk_use_mb;
+
+/*
+ *--------------------------------------------------------------
+ * gdk_set_locale
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gchar*
+gdk_set_locale (void)
+{
+  wchar_t result;
+  gchar *current_locale;
+
+  gdk_use_mb = FALSE;
+
+  if (!setlocale (LC_ALL,""))
+    g_warning ("locale not supported by C library");
+  
+  current_locale = setlocale (LC_ALL, NULL);
+
+  if (MB_CUR_MAX > 1)
+    gdk_use_mb = TRUE;
+
+  GDK_NOTE (XIM, g_message ("%s multi-byte string functions.", 
+                           gdk_use_mb ? "Using" : "Not using"));
+  
+  return current_locale;
+}
+
+void 
+gdk_im_begin (GdkIC *ic, GdkWindow* window)
+{
+}
+
+void 
+gdk_im_end (void)
+{
+}
+
+GdkIMStyle
+gdk_im_decide_style (GdkIMStyle supported_style)
+{
+  return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
+}
+
+GdkIMStyle
+gdk_im_set_best_style (GdkIMStyle style)
+{
+  return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
+}
+
+gint 
+gdk_im_ready (void)
+{
+  return FALSE;
+}
+
+GdkIC * 
+gdk_ic_new (GdkICAttr *attr, GdkICAttributesType mask)
+{
+  return NULL;
+}
+
+void 
+gdk_ic_destroy (GdkIC *ic)
+{
+}
+
+GdkIMStyle
+gdk_ic_get_style (GdkIC *ic)
+{
+  return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
+}
+
+void 
+gdk_ic_set_values (GdkIC *ic, ...)
+{
+}
+
+void 
+gdk_ic_get_values (GdkIC *ic, ...)
+{
+}
+
+GdkICAttributesType 
+gdk_ic_set_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
+{
+  return 0;
+}
+
+GdkICAttributesType 
+gdk_ic_get_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
+{
+  return 0;
+}
+
+GdkEventMask 
+gdk_ic_get_events (GdkIC *ic)
+{
+  return 0;
+}
+
+/*
+ * gdk_wcstombs 
+ *
+ * Returns a multi-byte string converted from the specified array
+ * of wide characters. The string is newly allocated. The array of
+ * wide characters must be null-terminated. If the conversion is
+ * failed, it returns NULL.
+ */
+gchar *
+gdk_wcstombs (const GdkWChar *src)
+{
+  gchar *mbstr;
+
+  if (gdk_use_mb)
+    {
+      gint i, wcsl, mbsl;
+      wchar_t *src_alt;
+
+      for (wcsl = 0; src[wcsl]; wcsl++)
+       ;
+      src_alt = g_new (wchar_t, wcsl+1);
+      for (i = wcsl; i >= 0; i--)
+       src_alt[i] = src[i];
+      mbsl = WideCharToMultiByte (CP_ACP, 0, src_alt, wcsl,
+                                 NULL, 0, NULL, NULL);
+      mbstr = g_new (guchar, mbsl + 1);
+      if (!WideCharToMultiByte (CP_ACP, 0, src_alt, wcsl,
+                               mbstr, mbsl, NULL, NULL))
+       {
+         g_warning ("gdk_wcstombs: WideCharToMultiByte failed");
+         g_free (mbstr);
+         g_free (src_alt);
+         return NULL;
+       }
+      mbstr[mbsl] = '\0';
+      g_free (src_alt);
+      return mbstr;
+    }
+  else
+    {
+      gint length = 0;
+      gint i;
+
+      while (src[length] != 0)
+       length++;
+      
+      mbstr = g_new (gchar, length + 1);
+
+      for (i=0; i<length+1; i++)
+       mbstr[i] = src[i];
+    }
+
+  return mbstr;
+}
+
+  
+/*
+ * gdk_mbstowcs
+ *
+ * Converts the specified string into wide characters, and, returns the
+ * number of wide characters written. The string 'src' must be
+ * null-terminated. If the conversion is failed, it returns -1.
+ */
+gint
+gdk_mbstowcs (GdkWChar *dest, const gchar *src, gint dest_max)
+{
+  if (gdk_use_mb)
+    {
+      gint i, wcsl;
+      wchar_t *wcstr;
+
+      wcsl = MultiByteToWideChar (CP_ACP, 0, src, -1, NULL, 0);
+      wcstr = g_new (wchar_t, wcsl + 1);
+      if (!MultiByteToWideChar (CP_ACP, 0, src, -1, wcstr, wcsl))
+       {
+         g_warning ("gdk_mbstowcs: MultiByteToWideChar failed");
+         g_free (wcstr);
+         return -1;
+       }
+      if (wcsl > dest_max)
+       wcsl = dest_max;
+      for (i = 0; i < wcsl; i++)
+       dest[i] = wcstr[i];
+
+      return wcsl;
+    }
+  else
+    {
+      gint i;
+
+      for (i=0; i<dest_max && src[i]; i++)
+       dest[i] = src[i];
+
+      return i;
+    }
+}
diff --git a/gdk/win32/gdkim.c b/gdk/win32/gdkim.c
new file mode 100644 (file)
index 0000000..e3f6e09
--- /dev/null
@@ -0,0 +1,248 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#  if STDC_HEADERS
+#    include <string.h>
+#  endif
+#endif
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdki18n.h"
+#include "gdkx.h"
+
+/* If this variable is FALSE, it indicates that we should
+ * avoid trying to use multibyte conversion functions and
+ * assume everything is 1-byte per character
+ */
+static gboolean gdk_use_mb;
+
+/*
+ *--------------------------------------------------------------
+ * gdk_set_locale
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gchar*
+gdk_set_locale (void)
+{
+  wchar_t result;
+  gchar *current_locale;
+
+  gdk_use_mb = FALSE;
+
+  if (!setlocale (LC_ALL,""))
+    g_warning ("locale not supported by C library");
+  
+  current_locale = setlocale (LC_ALL, NULL);
+
+  if (MB_CUR_MAX > 1)
+    gdk_use_mb = TRUE;
+
+  GDK_NOTE (XIM, g_message ("%s multi-byte string functions.", 
+                           gdk_use_mb ? "Using" : "Not using"));
+  
+  return current_locale;
+}
+
+void 
+gdk_im_begin (GdkIC *ic, GdkWindow* window)
+{
+}
+
+void 
+gdk_im_end (void)
+{
+}
+
+GdkIMStyle
+gdk_im_decide_style (GdkIMStyle supported_style)
+{
+  return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
+}
+
+GdkIMStyle
+gdk_im_set_best_style (GdkIMStyle style)
+{
+  return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
+}
+
+gint 
+gdk_im_ready (void)
+{
+  return FALSE;
+}
+
+GdkIC * 
+gdk_ic_new (GdkICAttr *attr, GdkICAttributesType mask)
+{
+  return NULL;
+}
+
+void 
+gdk_ic_destroy (GdkIC *ic)
+{
+}
+
+GdkIMStyle
+gdk_ic_get_style (GdkIC *ic)
+{
+  return GDK_IM_PREEDIT_NONE | GDK_IM_STATUS_NONE;
+}
+
+void 
+gdk_ic_set_values (GdkIC *ic, ...)
+{
+}
+
+void 
+gdk_ic_get_values (GdkIC *ic, ...)
+{
+}
+
+GdkICAttributesType 
+gdk_ic_set_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
+{
+  return 0;
+}
+
+GdkICAttributesType 
+gdk_ic_get_attr (GdkIC *ic, GdkICAttr *attr, GdkICAttributesType mask)
+{
+  return 0;
+}
+
+GdkEventMask 
+gdk_ic_get_events (GdkIC *ic)
+{
+  return 0;
+}
+
+/*
+ * gdk_wcstombs 
+ *
+ * Returns a multi-byte string converted from the specified array
+ * of wide characters. The string is newly allocated. The array of
+ * wide characters must be null-terminated. If the conversion is
+ * failed, it returns NULL.
+ */
+gchar *
+gdk_wcstombs (const GdkWChar *src)
+{
+  gchar *mbstr;
+
+  if (gdk_use_mb)
+    {
+      gint i, wcsl, mbsl;
+      wchar_t *src_alt;
+
+      for (wcsl = 0; src[wcsl]; wcsl++)
+       ;
+      src_alt = g_new (wchar_t, wcsl+1);
+      for (i = wcsl; i >= 0; i--)
+       src_alt[i] = src[i];
+      mbsl = WideCharToMultiByte (CP_ACP, 0, src_alt, wcsl,
+                                 NULL, 0, NULL, NULL);
+      mbstr = g_new (guchar, mbsl + 1);
+      if (!WideCharToMultiByte (CP_ACP, 0, src_alt, wcsl,
+                               mbstr, mbsl, NULL, NULL))
+       {
+         g_warning ("gdk_wcstombs: WideCharToMultiByte failed");
+         g_free (mbstr);
+         g_free (src_alt);
+         return NULL;
+       }
+      mbstr[mbsl] = '\0';
+      g_free (src_alt);
+      return mbstr;
+    }
+  else
+    {
+      gint length = 0;
+      gint i;
+
+      while (src[length] != 0)
+       length++;
+      
+      mbstr = g_new (gchar, length + 1);
+
+      for (i=0; i<length+1; i++)
+       mbstr[i] = src[i];
+    }
+
+  return mbstr;
+}
+
+  
+/*
+ * gdk_mbstowcs
+ *
+ * Converts the specified string into wide characters, and, returns the
+ * number of wide characters written. The string 'src' must be
+ * null-terminated. If the conversion is failed, it returns -1.
+ */
+gint
+gdk_mbstowcs (GdkWChar *dest, const gchar *src, gint dest_max)
+{
+  if (gdk_use_mb)
+    {
+      gint i, wcsl;
+      wchar_t *wcstr;
+
+      wcsl = MultiByteToWideChar (CP_ACP, 0, src, -1, NULL, 0);
+      wcstr = g_new (wchar_t, wcsl + 1);
+      if (!MultiByteToWideChar (CP_ACP, 0, src, -1, wcstr, wcsl))
+       {
+         g_warning ("gdk_mbstowcs: MultiByteToWideChar failed");
+         g_free (wcstr);
+         return -1;
+       }
+      if (wcsl > dest_max)
+       wcsl = dest_max;
+      for (i = 0; i < wcsl; i++)
+       dest[i] = wcstr[i];
+
+      return wcsl;
+    }
+  else
+    {
+      gint i;
+
+      for (i=0; i<dest_max && src[i]; i++)
+       dest[i] = src[i];
+
+      return i;
+    }
+}
diff --git a/gdk/win32/gdkimage-win32.c b/gdk/win32/gdkimage-win32.c
new file mode 100644 (file)
index 0000000..3719609
--- /dev/null
@@ -0,0 +1,760 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdk.h"
+#include "gdkprivate.h"
+
+static void gdk_image_put_normal (GdkDrawable *drawable,
+                                 GdkGC       *gc,
+                                 GdkImage    *image,
+                                 gint         xsrc,
+                                 gint         ysrc,
+                                 gint         xdest,
+                                 gint         ydest,
+                                 gint         width,
+                                 gint         height);
+static GList *image_list = NULL;
+
+void
+gdk_image_exit (void)
+{
+  GdkImage *image;
+
+  while (image_list)
+    {
+      image = image_list->data;
+      gdk_image_destroy (image);
+    }
+}
+
+GdkImage *
+gdk_image_new_bitmap (GdkVisual *visual, gpointer data, gint w, gint h)
+/*
+ * Desc: create a new bitmap image
+ */
+{
+  Visual *xvisual;
+  GdkImage *image;
+  GdkImagePrivate *private;
+  struct {
+    BITMAPINFOHEADER bmiHeader;
+    union {
+      WORD bmiIndices[2];
+      RGBQUAD bmiColors[2];
+    } u;
+  } bmi;
+  char *bits;
+  int bpl = (w-1)/8 + 1;
+  int bpl32 = ((w-1)/32 + 1)*4;
+
+  private = g_new(GdkImagePrivate, 1);
+  image = (GdkImage *) private;
+  private->image_put = gdk_image_put_normal;
+  image->type = GDK_IMAGE_NORMAL;
+  image->visual = visual;
+  image->width = w;
+  image->height = h;
+  image->depth = 1;
+  xvisual = ((GdkVisualPrivate*) visual)->xvisual;
+
+  GDK_NOTE (MISC, g_print ("gdk_image_new_bitmap: %dx%d\n", w, h));
+  
+  bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+  bmi.bmiHeader.biWidth = w;
+  bmi.bmiHeader.biHeight = -h;
+  bmi.bmiHeader.biPlanes = 1;
+  bmi.bmiHeader.biBitCount = 1;
+  bmi.bmiHeader.biCompression = BI_RGB;
+  bmi.bmiHeader.biSizeImage = 0;
+  bmi.bmiHeader.biXPelsPerMeter =
+    bmi.bmiHeader.biYPelsPerMeter = 0;
+  bmi.bmiHeader.biClrUsed = 0;
+  bmi.bmiHeader.biClrImportant = 0;
+  
+  bmi.u.bmiColors[0].rgbBlue = 
+    bmi.u.bmiColors[0].rgbGreen = 
+    bmi.u.bmiColors[0].rgbRed = 0x00;
+  bmi.u.bmiColors[0].rgbReserved = 0x00;
+
+  bmi.u.bmiColors[1].rgbBlue = 
+    bmi.u.bmiColors[1].rgbGreen = 
+    bmi.u.bmiColors[1].rgbRed = 0xFF;
+  bmi.u.bmiColors[1].rgbReserved = 0x00;
+  
+  private->ximage = CreateDIBSection (gdk_DC, (BITMAPINFO *) &bmi,
+                                     DIB_RGB_COLORS, &bits, NULL, 0);
+  if (bpl != bpl32)
+    {
+      /* Win32 expects scanlines in DIBs to be 32 bit aligned */
+      int i;
+      for (i = 0; i < h; i++)
+       memmove (bits + i*bpl32, ((char *) data) + i*bpl, bpl);
+    }
+  else
+    memmove (bits, data, bpl*h);
+  image->mem = bits;
+  image->bpl = bpl32;
+  image->byte_order = GDK_MSB_FIRST;
+
+  image->bpp = 1;
+  return(image);
+} /* gdk_image_new_bitmap() */
+
+void
+gdk_image_init (void)
+{
+}
+
+static GdkImage*
+gdk_image_new_with_depth (GdkImageType  type,
+                         GdkVisual    *visual,
+                         gint          width,
+                         gint          height,
+                         gint          depth)
+{
+  GdkImage *image;
+  GdkImagePrivate *private;
+  Visual *xvisual;
+  struct {
+    BITMAPINFOHEADER bmiHeader;
+    union {
+      WORD bmiIndices[256];
+      DWORD bmiMasks[3];
+      RGBQUAD bmiColors[256];
+    } u;
+  } bmi;
+  UINT iUsage;
+  int i;
+
+  GDK_NOTE (MISC, g_print ("gdk_image_new_with_depth: %dx%dx%d\n",
+                          width, height, depth));
+
+  switch (type)
+    {
+    case GDK_IMAGE_FASTEST:
+      image = gdk_image_new_with_depth (GDK_IMAGE_SHARED, visual,
+                                       width, height, depth);
+
+      if (!image)
+       image = gdk_image_new_with_depth (GDK_IMAGE_NORMAL, visual,
+                                         width, height, depth);
+      break;
+
+    default:
+      private = g_new (GdkImagePrivate, 1);
+      image = (GdkImage*) private;
+
+      private->image_put = NULL;
+
+      image->type = type;
+      image->visual = visual;
+      image->width = width;
+      image->height = height;
+      image->depth = depth;
+
+      xvisual = ((GdkVisualPrivate*) visual)->xvisual;
+
+      switch (type)
+       {
+       case GDK_IMAGE_SHARED:
+       case GDK_IMAGE_SHARED_PIXMAP:
+         /* Fall through, Windows images are always shared */
+       case GDK_IMAGE_NORMAL:
+         private->image_put = gdk_image_put_normal;
+
+         bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+         bmi.bmiHeader.biWidth = width;
+         bmi.bmiHeader.biHeight = -height;
+         bmi.bmiHeader.biPlanes = 1;
+         if (depth == 15)
+           bmi.bmiHeader.biBitCount = 16;
+         else
+           bmi.bmiHeader.biBitCount = depth;
+#if 1
+         if (depth == 16)
+           bmi.bmiHeader.biCompression = BI_BITFIELDS;
+         else
+#endif
+           bmi.bmiHeader.biCompression = BI_RGB;
+         bmi.bmiHeader.biSizeImage = 0;
+         bmi.bmiHeader.biXPelsPerMeter =
+           bmi.bmiHeader.biYPelsPerMeter = 0;
+         bmi.bmiHeader.biClrUsed = 0;
+         bmi.bmiHeader.biClrImportant = 0;
+         
+         if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR)
+           {
+             iUsage = DIB_PAL_COLORS;
+             for (i = 0; i < 256; i++)
+               bmi.u.bmiIndices[i] = i;
+           }
+         else
+           {
+             if (depth == 1)
+               {
+                 bmi.u.bmiColors[0].rgbBlue = 
+                   bmi.u.bmiColors[0].rgbGreen =
+                   bmi.u.bmiColors[0].rgbRed = 0x00;
+                 bmi.u.bmiColors[0].rgbReserved = 0x00;
+                 
+                 bmi.u.bmiColors[1].rgbBlue = 
+                   bmi.u.bmiColors[1].rgbGreen =
+                   bmi.u.bmiColors[1].rgbRed = 0xFF;
+                 bmi.u.bmiColors[1].rgbReserved = 0x00;
+                 
+               }
+#if 1
+             else if (depth == 16)
+               {
+                 bmi.u.bmiMasks[0] = visual->red_mask;
+                 bmi.u.bmiMasks[1] = visual->green_mask;
+                 bmi.u.bmiMasks[2] = visual->blue_mask;
+               }
+#endif
+             iUsage = DIB_RGB_COLORS;
+           }
+         
+         private->ximage =
+           CreateDIBSection (gdk_DC, (BITMAPINFO *) &bmi, iUsage,
+                             &image->mem, NULL, 0);
+         
+         if (private->ximage == NULL)
+           {
+             g_warning ("gdk_image_new_with_depth: CreateDIBSection failed");
+             g_free (image);
+             return NULL;
+           }
+         
+         switch (depth)
+           {
+           case 1:
+           case 8:
+             image->bpp = 1;
+             break;
+           case 15:
+           case 16:
+             image->bpp = 2;
+             break;
+           case 24:
+             image->bpp = 3;
+             break;
+           case 32:
+             image->bpp = 4;
+             break;
+           default:
+             g_warning ("gdk_image_new_with_depth: depth = %d", depth);
+             g_assert_not_reached ();
+           }
+         image->byte_order = GDK_LSB_FIRST;
+         if (depth == 1)
+           image->bpl = ((width-1)/32 + 1)*4;
+         else
+           image->bpl = ((width*image->bpp - 1)/4 + 1)*4;
+
+         GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n",
+                                  private->ximage, image->mem, image->bpl));
+
+         break;
+
+       case GDK_IMAGE_FASTEST:
+         g_assert_not_reached ();
+       }
+      
+      break;
+    }
+
+  return image;
+}
+
+GdkImage*
+gdk_image_new (GdkImageType  type,
+              GdkVisual    *visual,
+              gint          width,
+              gint          height)
+{
+  return gdk_image_new_with_depth (type, visual, width, height, visual->depth);
+}
+
+GdkImage*
+gdk_image_bitmap_new (GdkImageType  type,
+                     GdkVisual    *visual,
+                     gint          width,
+                     gint          height)
+{
+  return gdk_image_new_with_depth (type, visual, width, height, 1);
+}
+
+GdkImage*
+gdk_image_get (GdkWindow *window,
+              gint       x,
+              gint       y,
+              gint       width,
+              gint       height)
+{
+  GdkImage *image;
+  GdkImagePrivate *private;
+  GdkWindowPrivate *win_private;
+  HDC hdc, memdc;
+  struct {
+    BITMAPINFOHEADER bmiHeader;
+    union {
+      WORD bmiIndices[256];
+      DWORD bmiMasks[3];
+      RGBQUAD bmiColors[256];
+    } u;
+  } bmi;
+  HGDIOBJ oldbitmap1, oldbitmap2;
+  UINT iUsage;
+  BITMAP bm;
+  int i;
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  win_private = (GdkWindowPrivate *) window;
+  if (win_private->destroyed)
+    return NULL;
+
+  GDK_NOTE (MISC, g_print ("gdk_image_get: %#x %dx%d@+%d+%d\n",
+                          win_private->xwindow, width, height, x, y));
+
+  private = g_new (GdkImagePrivate, 1);
+  image = (GdkImage*) private;
+
+  private->image_put = gdk_image_put_normal;
+
+  image->type = GDK_IMAGE_NORMAL;
+  image->visual = gdk_window_get_visual (window);
+  image->width = width;
+  image->height = height;
+
+  /* This function is called both to blit from a window and from
+   * a pixmap.
+   */
+  if (win_private->window_type == GDK_WINDOW_PIXMAP)
+    {
+      if ((hdc = CreateCompatibleDC (NULL)) == NULL)
+       {
+         g_warning ("gdk_image_get: CreateCompatibleDC #1 failed");
+         g_free (image);
+         return NULL;
+       }
+      if ((oldbitmap1 = SelectObject (hdc, win_private->xwindow)) == NULL)
+       {
+         g_warning ("gdk_image_get: SelectObject #1 failed");
+         DeleteDC (hdc);
+         g_free (image);
+         return NULL;
+       }
+      GetObject (win_private->xwindow, sizeof (BITMAP), &bm);
+      GDK_NOTE (MISC,
+               g_print ("gdk_image_get: bmWidth = %d, bmHeight = %d, bmWidthBytes = %d, bmBitsPixel = %d\n",
+                        bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, bm.bmBitsPixel));
+      image->depth = bm.bmBitsPixel;
+      if (image->depth <= 8)
+       {
+         iUsage = DIB_PAL_COLORS;
+         for (i = 0; i < 256; i++)
+           bmi.u.bmiIndices[i] = i;
+       }
+      else
+       iUsage = DIB_RGB_COLORS;
+    }
+  else
+    {
+      if ((hdc = GetDC (win_private->xwindow)) == NULL)
+       {
+         g_warning ("gdk_image_get: GetDC failed");
+         g_free (image);
+         return NULL;
+       }
+      image->depth = gdk_visual_get_system ()->depth;
+      if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR)
+       {
+         iUsage = DIB_PAL_COLORS;
+         for (i = 0; i < 256; i++)
+           bmi.u.bmiIndices[i] = i;
+       }
+      else
+       iUsage = DIB_RGB_COLORS;
+    }
+
+  if ((memdc = CreateCompatibleDC (hdc)) == NULL)
+    {
+      g_warning ("gdk_image_get: CreateCompatibleDC #2 failed");
+      if (win_private->window_type == GDK_WINDOW_PIXMAP)
+       {
+         SelectObject (hdc, oldbitmap1);
+         DeleteDC (hdc);
+       }
+      else
+       {
+         ReleaseDC (win_private->xwindow, hdc);
+       }
+      g_free (image);
+      return NULL;
+    }
+
+  bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+  bmi.bmiHeader.biWidth = width;
+  bmi.bmiHeader.biHeight = -height;
+  bmi.bmiHeader.biPlanes = 1;
+  bmi.bmiHeader.biBitCount = image->depth;
+  bmi.bmiHeader.biCompression = BI_RGB;
+  bmi.bmiHeader.biSizeImage = 0;
+  bmi.bmiHeader.biXPelsPerMeter =
+    bmi.bmiHeader.biYPelsPerMeter = 0;
+  bmi.bmiHeader.biClrUsed = 0;
+  bmi.bmiHeader.biClrImportant = 0;
+
+  if ((private->ximage =
+       CreateDIBSection (hdc, (BITMAPINFO *) &bmi, iUsage,
+                        &image->mem, NULL, 0)) == NULL)
+    {
+      g_warning ("gdk_image_get: CreateDIBSection failed");
+      DeleteDC (memdc);
+      if (win_private->window_type == GDK_WINDOW_PIXMAP)
+       {
+         SelectObject (hdc, oldbitmap1);
+         DeleteDC (hdc);
+       }
+      else
+       {
+         ReleaseDC (win_private->xwindow, hdc);
+       }
+      g_free (image);
+      return NULL;
+    }
+
+  if ((oldbitmap2 = SelectObject (memdc, private->ximage)) == NULL)
+    {
+      g_warning ("gdk_image_get: SelectObject #2 failed");
+      DeleteObject (private->ximage);
+      DeleteDC (memdc);
+      if (win_private->window_type == GDK_WINDOW_PIXMAP)
+       {
+         SelectObject (hdc, oldbitmap1);
+         DeleteDC (hdc);
+       }
+      else
+       {
+         ReleaseDC (win_private->xwindow, hdc);
+       }
+      g_free (image);
+      return NULL;
+    }
+
+  if (!BitBlt (memdc, 0, 0, width, height, hdc, x, y, SRCCOPY))
+    {
+      g_warning ("gdk_image_get: BitBlt failed");
+      SelectObject (memdc, oldbitmap2);
+      DeleteObject (private->ximage);
+      DeleteDC (memdc);
+      if (win_private->window_type == GDK_WINDOW_PIXMAP)
+       {
+         SelectObject (hdc, oldbitmap1);
+         DeleteDC (hdc);
+       }
+      else
+       {
+         ReleaseDC (win_private->xwindow, hdc);
+       }
+      g_free (image);
+      return NULL;
+    }
+
+  if (SelectObject (memdc, oldbitmap2) == NULL)
+    g_warning ("gdk_image_get: SelectObject #3 failed");
+
+  if (!DeleteDC (memdc))
+    g_warning ("gdk_image_get: DeleteDC failed");
+
+  if (win_private->window_type == GDK_WINDOW_PIXMAP)
+    {
+      SelectObject (hdc, oldbitmap1);
+      DeleteDC (hdc);
+    }
+  else
+    {
+      ReleaseDC (win_private->xwindow, hdc);
+    }
+
+  switch (image->depth)
+    {
+    case 1:
+    case 8:
+      image->bpp = 1;
+      break;
+    case 15:
+    case 16:
+      image->bpp = 2;
+      break;
+    case 24:
+      image->bpp = 3;
+      break;
+    case 32:
+      image->bpp = 4;
+      break;
+    default:
+      g_warning ("gdk_image_get: image->depth = %d", image->depth);
+      g_assert_not_reached ();
+    }
+  image->byte_order = GDK_LSB_FIRST;
+  if (image->depth == 1)
+    image->bpl = (width - 1)/8 + 1;
+  else
+    image->bpl = ((width*image->bpp - 1)/4 + 1)*4;
+
+  GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n",
+                          private->ximage, image->mem, image->bpl));
+
+  return image;
+}
+
+guint32
+gdk_image_get_pixel (GdkImage *image,
+                    gint x,
+                    gint y)
+{
+  guint32 pixel;
+  GdkImagePrivate *private;
+
+  g_return_val_if_fail (image != NULL, 0);
+
+  private = (GdkImagePrivate *) image;
+
+  g_return_val_if_fail (x >= 0 && x < image->width
+                       && y >= 0 && y < image->height, 0);
+
+  if (image->depth == 1)
+    pixel = (((char *) image->mem)[y * image->bpl + (x >> 3)] & (1 << (7 - (x & 0x7)))) != 0;
+  else
+    {
+      guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp;
+      
+      switch (image->bpp)
+       {
+       case 1:
+         pixel = *pixelp;
+         break;
+
+       /* Windows is always LSB, no need to check image->byte_order. */
+       case 2:
+         pixel = pixelp[0] | (pixelp[1] << 8);
+         break;
+
+       case 3:
+         pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
+         break;
+
+       case 4:
+         pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
+         break;
+       }
+    }
+
+  return pixel;
+}
+
+void
+gdk_image_put_pixel (GdkImage *image,
+                    gint x,
+                    gint y,
+                    guint32 pixel)
+{
+  GdkImagePrivate *private;
+
+  g_return_if_fail (image != NULL);
+
+  private = (GdkImagePrivate *) image;
+
+  g_return_if_fail (x >= 0 && x < image->width && y >= 0 && y < image->height);
+
+  if (image->depth == 1)
+    if (pixel & 1)
+      ((guchar *) image->mem)[y * image->bpl + (x >> 3)] |= (1 << (7 - (x & 0x7)));
+    else
+      ((guchar *) image->mem)[y * image->bpl + (x >> 3)] &= ~(1 << (7 - (x & 0x7)));
+  else
+    {
+      guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp;
+      
+      /* Windows is always LSB, no need to check image->byte_order. */
+      switch (image->bpp)
+       {
+       case 4:
+         pixelp[3] = 0;
+       case 3:
+         pixelp[2] = ((pixel >> 16) & 0xFF);
+       case 2:
+         pixelp[1] = ((pixel >> 8) & 0xFF);
+       case 1:
+         pixelp[0] = (pixel & 0xFF);
+       }
+    }
+}
+
+void
+gdk_image_destroy (GdkImage *image)
+{
+  GdkImagePrivate *private;
+
+  g_return_if_fail (image != NULL);
+
+  private = (GdkImagePrivate*) image;
+
+  GDK_NOTE (MISC, g_print ("gdk_image_destroy: %#x%s\n",
+                          private->ximage,
+                          (image->type == GDK_IMAGE_SHARED_PIXMAP ?
+                           " (shared pixmap)" : "")));
+  
+  switch (image->type)
+    {
+    case GDK_IMAGE_NORMAL:
+    case GDK_IMAGE_SHARED_PIXMAP:
+      break;                   /* The Windows bitmap has already been
+                                * (or will be) deleted when freeing
+                                * the corresponding pixmap.
+                                */
+
+    case GDK_IMAGE_SHARED:     /* All images are shared in Windows */
+      DeleteObject (private->ximage);
+      break;
+
+    case GDK_IMAGE_FASTEST:
+      g_assert_not_reached ();
+    }
+
+  g_free (image);
+}
+
+static void
+gdk_image_put_normal (GdkDrawable *drawable,
+                     GdkGC       *gc,
+                     GdkImage    *image,
+                     gint         xsrc,
+                     gint         ysrc,
+                     gint         xdest,
+                     gint         ydest,
+                     gint         width,
+                     gint         height)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkImagePrivate *image_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  GdkColormapPrivate *colormap_private;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (image != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  image_private = (GdkImagePrivate*) image;
+  gc_private = (GdkGCPrivate*) gc;
+
+  /* The image can in fact be "shared", so don't test */
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+  colormap_private = (GdkColormapPrivate *) drawable_private->colormap;
+  if (colormap_private && colormap_private->xcolormap->rc_palette)
+    {
+      DIBSECTION ds;
+      static struct {
+       BITMAPINFOHEADER bmiHeader;
+       WORD bmiIndices[256];
+      } bmi;
+      static gboolean bmi_inited = FALSE;
+      int i;
+
+      if (!bmi_inited)
+       {
+         for (i = 0; i < 256; i++)
+           bmi.bmiIndices[i] = i;
+         bmi_inited = TRUE;
+       }
+
+      if (GetObject (image_private->ximage, sizeof (DIBSECTION),
+                    &ds) != sizeof (DIBSECTION))
+       {
+         g_warning ("gdk_image_put_normal: GetObject failed");
+       }
+#if 0
+      g_print("xdest = %d, ydest = %d, xsrc = %d, ysrc = %d, width = %d, height = %d\n",
+             xdest, ydest, xsrc, ysrc, width, height);
+      g_print("bmWidth = %d, bmHeight = %d, bmBitsPixel = %d, bmBits = %p\n",
+             ds.dsBm.bmWidth, ds.dsBm.bmHeight, ds.dsBm.bmBitsPixel, ds.dsBm.bmBits);
+      g_print("biWidth = %d, biHeight = %d, biBitCount = %d, biClrUsed = %d\n",
+             ds.dsBmih.biWidth, ds.dsBmih.biHeight, ds.dsBmih.biBitCount, ds.dsBmih.biClrUsed);
+#endif
+      bmi.bmiHeader = ds.dsBmih;
+      /* I have spent hours on getting the parameters to
+       * SetDIBitsToDevice right. I wonder what drugs the guys in
+       * Redmond were on when they designed this API.
+       */
+      if (SetDIBitsToDevice (hdc,
+                            xdest, ydest,
+                            width, height,
+                            xsrc, (-ds.dsBmih.biHeight)-height-ysrc,
+                            0, -ds.dsBmih.biHeight,
+                            ds.dsBm.bmBits,
+                            (CONST BITMAPINFO *) &bmi,
+                            DIB_PAL_COLORS) == 0)
+       g_warning ("SetDIBitsToDevice failed");
+    }
+  else
+    {
+      HDC memdc;
+      HGDIOBJ oldbitmap;
+
+      if ((memdc = CreateCompatibleDC (hdc)) == NULL)
+       {
+         g_warning ("gdk_image_put_normal: CreateCompatibleDC failed");
+         gdk_gc_postdraw (drawable_private, gc_private);
+         return;
+       }
+
+      if ((oldbitmap = SelectObject (memdc, image_private->ximage)) == NULL)
+       {
+         g_warning ("gdk_image_put_normal: SelectObject #1 failed");
+         gdk_gc_postdraw (drawable_private, gc_private);
+         return;
+       }
+      if (!BitBlt (hdc, xdest, ydest, width, height,
+                  memdc, xsrc, ysrc, SRCCOPY))
+       g_warning ("gdk_image_put_normal: BitBlt failed");
+
+      if (SelectObject (memdc, oldbitmap) == NULL)
+       g_warning ("gdk_image_put_normal: SelectObject #2 failed");
+
+      if (!DeleteDC (memdc))
+       g_warning ("gdk_image_put_normal: DeleteDC failed");
+    }
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
diff --git a/gdk/win32/gdkimage.c b/gdk/win32/gdkimage.c
new file mode 100644 (file)
index 0000000..3719609
--- /dev/null
@@ -0,0 +1,760 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdk.h"
+#include "gdkprivate.h"
+
+static void gdk_image_put_normal (GdkDrawable *drawable,
+                                 GdkGC       *gc,
+                                 GdkImage    *image,
+                                 gint         xsrc,
+                                 gint         ysrc,
+                                 gint         xdest,
+                                 gint         ydest,
+                                 gint         width,
+                                 gint         height);
+static GList *image_list = NULL;
+
+void
+gdk_image_exit (void)
+{
+  GdkImage *image;
+
+  while (image_list)
+    {
+      image = image_list->data;
+      gdk_image_destroy (image);
+    }
+}
+
+GdkImage *
+gdk_image_new_bitmap (GdkVisual *visual, gpointer data, gint w, gint h)
+/*
+ * Desc: create a new bitmap image
+ */
+{
+  Visual *xvisual;
+  GdkImage *image;
+  GdkImagePrivate *private;
+  struct {
+    BITMAPINFOHEADER bmiHeader;
+    union {
+      WORD bmiIndices[2];
+      RGBQUAD bmiColors[2];
+    } u;
+  } bmi;
+  char *bits;
+  int bpl = (w-1)/8 + 1;
+  int bpl32 = ((w-1)/32 + 1)*4;
+
+  private = g_new(GdkImagePrivate, 1);
+  image = (GdkImage *) private;
+  private->image_put = gdk_image_put_normal;
+  image->type = GDK_IMAGE_NORMAL;
+  image->visual = visual;
+  image->width = w;
+  image->height = h;
+  image->depth = 1;
+  xvisual = ((GdkVisualPrivate*) visual)->xvisual;
+
+  GDK_NOTE (MISC, g_print ("gdk_image_new_bitmap: %dx%d\n", w, h));
+  
+  bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+  bmi.bmiHeader.biWidth = w;
+  bmi.bmiHeader.biHeight = -h;
+  bmi.bmiHeader.biPlanes = 1;
+  bmi.bmiHeader.biBitCount = 1;
+  bmi.bmiHeader.biCompression = BI_RGB;
+  bmi.bmiHeader.biSizeImage = 0;
+  bmi.bmiHeader.biXPelsPerMeter =
+    bmi.bmiHeader.biYPelsPerMeter = 0;
+  bmi.bmiHeader.biClrUsed = 0;
+  bmi.bmiHeader.biClrImportant = 0;
+  
+  bmi.u.bmiColors[0].rgbBlue = 
+    bmi.u.bmiColors[0].rgbGreen = 
+    bmi.u.bmiColors[0].rgbRed = 0x00;
+  bmi.u.bmiColors[0].rgbReserved = 0x00;
+
+  bmi.u.bmiColors[1].rgbBlue = 
+    bmi.u.bmiColors[1].rgbGreen = 
+    bmi.u.bmiColors[1].rgbRed = 0xFF;
+  bmi.u.bmiColors[1].rgbReserved = 0x00;
+  
+  private->ximage = CreateDIBSection (gdk_DC, (BITMAPINFO *) &bmi,
+                                     DIB_RGB_COLORS, &bits, NULL, 0);
+  if (bpl != bpl32)
+    {
+      /* Win32 expects scanlines in DIBs to be 32 bit aligned */
+      int i;
+      for (i = 0; i < h; i++)
+       memmove (bits + i*bpl32, ((char *) data) + i*bpl, bpl);
+    }
+  else
+    memmove (bits, data, bpl*h);
+  image->mem = bits;
+  image->bpl = bpl32;
+  image->byte_order = GDK_MSB_FIRST;
+
+  image->bpp = 1;
+  return(image);
+} /* gdk_image_new_bitmap() */
+
+void
+gdk_image_init (void)
+{
+}
+
+static GdkImage*
+gdk_image_new_with_depth (GdkImageType  type,
+                         GdkVisual    *visual,
+                         gint          width,
+                         gint          height,
+                         gint          depth)
+{
+  GdkImage *image;
+  GdkImagePrivate *private;
+  Visual *xvisual;
+  struct {
+    BITMAPINFOHEADER bmiHeader;
+    union {
+      WORD bmiIndices[256];
+      DWORD bmiMasks[3];
+      RGBQUAD bmiColors[256];
+    } u;
+  } bmi;
+  UINT iUsage;
+  int i;
+
+  GDK_NOTE (MISC, g_print ("gdk_image_new_with_depth: %dx%dx%d\n",
+                          width, height, depth));
+
+  switch (type)
+    {
+    case GDK_IMAGE_FASTEST:
+      image = gdk_image_new_with_depth (GDK_IMAGE_SHARED, visual,
+                                       width, height, depth);
+
+      if (!image)
+       image = gdk_image_new_with_depth (GDK_IMAGE_NORMAL, visual,
+                                         width, height, depth);
+      break;
+
+    default:
+      private = g_new (GdkImagePrivate, 1);
+      image = (GdkImage*) private;
+
+      private->image_put = NULL;
+
+      image->type = type;
+      image->visual = visual;
+      image->width = width;
+      image->height = height;
+      image->depth = depth;
+
+      xvisual = ((GdkVisualPrivate*) visual)->xvisual;
+
+      switch (type)
+       {
+       case GDK_IMAGE_SHARED:
+       case GDK_IMAGE_SHARED_PIXMAP:
+         /* Fall through, Windows images are always shared */
+       case GDK_IMAGE_NORMAL:
+         private->image_put = gdk_image_put_normal;
+
+         bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+         bmi.bmiHeader.biWidth = width;
+         bmi.bmiHeader.biHeight = -height;
+         bmi.bmiHeader.biPlanes = 1;
+         if (depth == 15)
+           bmi.bmiHeader.biBitCount = 16;
+         else
+           bmi.bmiHeader.biBitCount = depth;
+#if 1
+         if (depth == 16)
+           bmi.bmiHeader.biCompression = BI_BITFIELDS;
+         else
+#endif
+           bmi.bmiHeader.biCompression = BI_RGB;
+         bmi.bmiHeader.biSizeImage = 0;
+         bmi.bmiHeader.biXPelsPerMeter =
+           bmi.bmiHeader.biYPelsPerMeter = 0;
+         bmi.bmiHeader.biClrUsed = 0;
+         bmi.bmiHeader.biClrImportant = 0;
+         
+         if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR)
+           {
+             iUsage = DIB_PAL_COLORS;
+             for (i = 0; i < 256; i++)
+               bmi.u.bmiIndices[i] = i;
+           }
+         else
+           {
+             if (depth == 1)
+               {
+                 bmi.u.bmiColors[0].rgbBlue = 
+                   bmi.u.bmiColors[0].rgbGreen =
+                   bmi.u.bmiColors[0].rgbRed = 0x00;
+                 bmi.u.bmiColors[0].rgbReserved = 0x00;
+                 
+                 bmi.u.bmiColors[1].rgbBlue = 
+                   bmi.u.bmiColors[1].rgbGreen =
+                   bmi.u.bmiColors[1].rgbRed = 0xFF;
+                 bmi.u.bmiColors[1].rgbReserved = 0x00;
+                 
+               }
+#if 1
+             else if (depth == 16)
+               {
+                 bmi.u.bmiMasks[0] = visual->red_mask;
+                 bmi.u.bmiMasks[1] = visual->green_mask;
+                 bmi.u.bmiMasks[2] = visual->blue_mask;
+               }
+#endif
+             iUsage = DIB_RGB_COLORS;
+           }
+         
+         private->ximage =
+           CreateDIBSection (gdk_DC, (BITMAPINFO *) &bmi, iUsage,
+                             &image->mem, NULL, 0);
+         
+         if (private->ximage == NULL)
+           {
+             g_warning ("gdk_image_new_with_depth: CreateDIBSection failed");
+             g_free (image);
+             return NULL;
+           }
+         
+         switch (depth)
+           {
+           case 1:
+           case 8:
+             image->bpp = 1;
+             break;
+           case 15:
+           case 16:
+             image->bpp = 2;
+             break;
+           case 24:
+             image->bpp = 3;
+             break;
+           case 32:
+             image->bpp = 4;
+             break;
+           default:
+             g_warning ("gdk_image_new_with_depth: depth = %d", depth);
+             g_assert_not_reached ();
+           }
+         image->byte_order = GDK_LSB_FIRST;
+         if (depth == 1)
+           image->bpl = ((width-1)/32 + 1)*4;
+         else
+           image->bpl = ((width*image->bpp - 1)/4 + 1)*4;
+
+         GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n",
+                                  private->ximage, image->mem, image->bpl));
+
+         break;
+
+       case GDK_IMAGE_FASTEST:
+         g_assert_not_reached ();
+       }
+      
+      break;
+    }
+
+  return image;
+}
+
+GdkImage*
+gdk_image_new (GdkImageType  type,
+              GdkVisual    *visual,
+              gint          width,
+              gint          height)
+{
+  return gdk_image_new_with_depth (type, visual, width, height, visual->depth);
+}
+
+GdkImage*
+gdk_image_bitmap_new (GdkImageType  type,
+                     GdkVisual    *visual,
+                     gint          width,
+                     gint          height)
+{
+  return gdk_image_new_with_depth (type, visual, width, height, 1);
+}
+
+GdkImage*
+gdk_image_get (GdkWindow *window,
+              gint       x,
+              gint       y,
+              gint       width,
+              gint       height)
+{
+  GdkImage *image;
+  GdkImagePrivate *private;
+  GdkWindowPrivate *win_private;
+  HDC hdc, memdc;
+  struct {
+    BITMAPINFOHEADER bmiHeader;
+    union {
+      WORD bmiIndices[256];
+      DWORD bmiMasks[3];
+      RGBQUAD bmiColors[256];
+    } u;
+  } bmi;
+  HGDIOBJ oldbitmap1, oldbitmap2;
+  UINT iUsage;
+  BITMAP bm;
+  int i;
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  win_private = (GdkWindowPrivate *) window;
+  if (win_private->destroyed)
+    return NULL;
+
+  GDK_NOTE (MISC, g_print ("gdk_image_get: %#x %dx%d@+%d+%d\n",
+                          win_private->xwindow, width, height, x, y));
+
+  private = g_new (GdkImagePrivate, 1);
+  image = (GdkImage*) private;
+
+  private->image_put = gdk_image_put_normal;
+
+  image->type = GDK_IMAGE_NORMAL;
+  image->visual = gdk_window_get_visual (window);
+  image->width = width;
+  image->height = height;
+
+  /* This function is called both to blit from a window and from
+   * a pixmap.
+   */
+  if (win_private->window_type == GDK_WINDOW_PIXMAP)
+    {
+      if ((hdc = CreateCompatibleDC (NULL)) == NULL)
+       {
+         g_warning ("gdk_image_get: CreateCompatibleDC #1 failed");
+         g_free (image);
+         return NULL;
+       }
+      if ((oldbitmap1 = SelectObject (hdc, win_private->xwindow)) == NULL)
+       {
+         g_warning ("gdk_image_get: SelectObject #1 failed");
+         DeleteDC (hdc);
+         g_free (image);
+         return NULL;
+       }
+      GetObject (win_private->xwindow, sizeof (BITMAP), &bm);
+      GDK_NOTE (MISC,
+               g_print ("gdk_image_get: bmWidth = %d, bmHeight = %d, bmWidthBytes = %d, bmBitsPixel = %d\n",
+                        bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, bm.bmBitsPixel));
+      image->depth = bm.bmBitsPixel;
+      if (image->depth <= 8)
+       {
+         iUsage = DIB_PAL_COLORS;
+         for (i = 0; i < 256; i++)
+           bmi.u.bmiIndices[i] = i;
+       }
+      else
+       iUsage = DIB_RGB_COLORS;
+    }
+  else
+    {
+      if ((hdc = GetDC (win_private->xwindow)) == NULL)
+       {
+         g_warning ("gdk_image_get: GetDC failed");
+         g_free (image);
+         return NULL;
+       }
+      image->depth = gdk_visual_get_system ()->depth;
+      if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR)
+       {
+         iUsage = DIB_PAL_COLORS;
+         for (i = 0; i < 256; i++)
+           bmi.u.bmiIndices[i] = i;
+       }
+      else
+       iUsage = DIB_RGB_COLORS;
+    }
+
+  if ((memdc = CreateCompatibleDC (hdc)) == NULL)
+    {
+      g_warning ("gdk_image_get: CreateCompatibleDC #2 failed");
+      if (win_private->window_type == GDK_WINDOW_PIXMAP)
+       {
+         SelectObject (hdc, oldbitmap1);
+         DeleteDC (hdc);
+       }
+      else
+       {
+         ReleaseDC (win_private->xwindow, hdc);
+       }
+      g_free (image);
+      return NULL;
+    }
+
+  bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+  bmi.bmiHeader.biWidth = width;
+  bmi.bmiHeader.biHeight = -height;
+  bmi.bmiHeader.biPlanes = 1;
+  bmi.bmiHeader.biBitCount = image->depth;
+  bmi.bmiHeader.biCompression = BI_RGB;
+  bmi.bmiHeader.biSizeImage = 0;
+  bmi.bmiHeader.biXPelsPerMeter =
+    bmi.bmiHeader.biYPelsPerMeter = 0;
+  bmi.bmiHeader.biClrUsed = 0;
+  bmi.bmiHeader.biClrImportant = 0;
+
+  if ((private->ximage =
+       CreateDIBSection (hdc, (BITMAPINFO *) &bmi, iUsage,
+                        &image->mem, NULL, 0)) == NULL)
+    {
+      g_warning ("gdk_image_get: CreateDIBSection failed");
+      DeleteDC (memdc);
+      if (win_private->window_type == GDK_WINDOW_PIXMAP)
+       {
+         SelectObject (hdc, oldbitmap1);
+         DeleteDC (hdc);
+       }
+      else
+       {
+         ReleaseDC (win_private->xwindow, hdc);
+       }
+      g_free (image);
+      return NULL;
+    }
+
+  if ((oldbitmap2 = SelectObject (memdc, private->ximage)) == NULL)
+    {
+      g_warning ("gdk_image_get: SelectObject #2 failed");
+      DeleteObject (private->ximage);
+      DeleteDC (memdc);
+      if (win_private->window_type == GDK_WINDOW_PIXMAP)
+       {
+         SelectObject (hdc, oldbitmap1);
+         DeleteDC (hdc);
+       }
+      else
+       {
+         ReleaseDC (win_private->xwindow, hdc);
+       }
+      g_free (image);
+      return NULL;
+    }
+
+  if (!BitBlt (memdc, 0, 0, width, height, hdc, x, y, SRCCOPY))
+    {
+      g_warning ("gdk_image_get: BitBlt failed");
+      SelectObject (memdc, oldbitmap2);
+      DeleteObject (private->ximage);
+      DeleteDC (memdc);
+      if (win_private->window_type == GDK_WINDOW_PIXMAP)
+       {
+         SelectObject (hdc, oldbitmap1);
+         DeleteDC (hdc);
+       }
+      else
+       {
+         ReleaseDC (win_private->xwindow, hdc);
+       }
+      g_free (image);
+      return NULL;
+    }
+
+  if (SelectObject (memdc, oldbitmap2) == NULL)
+    g_warning ("gdk_image_get: SelectObject #3 failed");
+
+  if (!DeleteDC (memdc))
+    g_warning ("gdk_image_get: DeleteDC failed");
+
+  if (win_private->window_type == GDK_WINDOW_PIXMAP)
+    {
+      SelectObject (hdc, oldbitmap1);
+      DeleteDC (hdc);
+    }
+  else
+    {
+      ReleaseDC (win_private->xwindow, hdc);
+    }
+
+  switch (image->depth)
+    {
+    case 1:
+    case 8:
+      image->bpp = 1;
+      break;
+    case 15:
+    case 16:
+      image->bpp = 2;
+      break;
+    case 24:
+      image->bpp = 3;
+      break;
+    case 32:
+      image->bpp = 4;
+      break;
+    default:
+      g_warning ("gdk_image_get: image->depth = %d", image->depth);
+      g_assert_not_reached ();
+    }
+  image->byte_order = GDK_LSB_FIRST;
+  if (image->depth == 1)
+    image->bpl = (width - 1)/8 + 1;
+  else
+    image->bpl = ((width*image->bpp - 1)/4 + 1)*4;
+
+  GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n",
+                          private->ximage, image->mem, image->bpl));
+
+  return image;
+}
+
+guint32
+gdk_image_get_pixel (GdkImage *image,
+                    gint x,
+                    gint y)
+{
+  guint32 pixel;
+  GdkImagePrivate *private;
+
+  g_return_val_if_fail (image != NULL, 0);
+
+  private = (GdkImagePrivate *) image;
+
+  g_return_val_if_fail (x >= 0 && x < image->width
+                       && y >= 0 && y < image->height, 0);
+
+  if (image->depth == 1)
+    pixel = (((char *) image->mem)[y * image->bpl + (x >> 3)] & (1 << (7 - (x & 0x7)))) != 0;
+  else
+    {
+      guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp;
+      
+      switch (image->bpp)
+       {
+       case 1:
+         pixel = *pixelp;
+         break;
+
+       /* Windows is always LSB, no need to check image->byte_order. */
+       case 2:
+         pixel = pixelp[0] | (pixelp[1] << 8);
+         break;
+
+       case 3:
+         pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
+         break;
+
+       case 4:
+         pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
+         break;
+       }
+    }
+
+  return pixel;
+}
+
+void
+gdk_image_put_pixel (GdkImage *image,
+                    gint x,
+                    gint y,
+                    guint32 pixel)
+{
+  GdkImagePrivate *private;
+
+  g_return_if_fail (image != NULL);
+
+  private = (GdkImagePrivate *) image;
+
+  g_return_if_fail (x >= 0 && x < image->width && y >= 0 && y < image->height);
+
+  if (image->depth == 1)
+    if (pixel & 1)
+      ((guchar *) image->mem)[y * image->bpl + (x >> 3)] |= (1 << (7 - (x & 0x7)));
+    else
+      ((guchar *) image->mem)[y * image->bpl + (x >> 3)] &= ~(1 << (7 - (x & 0x7)));
+  else
+    {
+      guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp;
+      
+      /* Windows is always LSB, no need to check image->byte_order. */
+      switch (image->bpp)
+       {
+       case 4:
+         pixelp[3] = 0;
+       case 3:
+         pixelp[2] = ((pixel >> 16) & 0xFF);
+       case 2:
+         pixelp[1] = ((pixel >> 8) & 0xFF);
+       case 1:
+         pixelp[0] = (pixel & 0xFF);
+       }
+    }
+}
+
+void
+gdk_image_destroy (GdkImage *image)
+{
+  GdkImagePrivate *private;
+
+  g_return_if_fail (image != NULL);
+
+  private = (GdkImagePrivate*) image;
+
+  GDK_NOTE (MISC, g_print ("gdk_image_destroy: %#x%s\n",
+                          private->ximage,
+                          (image->type == GDK_IMAGE_SHARED_PIXMAP ?
+                           " (shared pixmap)" : "")));
+  
+  switch (image->type)
+    {
+    case GDK_IMAGE_NORMAL:
+    case GDK_IMAGE_SHARED_PIXMAP:
+      break;                   /* The Windows bitmap has already been
+                                * (or will be) deleted when freeing
+                                * the corresponding pixmap.
+                                */
+
+    case GDK_IMAGE_SHARED:     /* All images are shared in Windows */
+      DeleteObject (private->ximage);
+      break;
+
+    case GDK_IMAGE_FASTEST:
+      g_assert_not_reached ();
+    }
+
+  g_free (image);
+}
+
+static void
+gdk_image_put_normal (GdkDrawable *drawable,
+                     GdkGC       *gc,
+                     GdkImage    *image,
+                     gint         xsrc,
+                     gint         ysrc,
+                     gint         xdest,
+                     gint         ydest,
+                     gint         width,
+                     gint         height)
+{
+  GdkWindowPrivate *drawable_private;
+  GdkImagePrivate *image_private;
+  GdkGCPrivate *gc_private;
+  HDC hdc;
+  GdkColormapPrivate *colormap_private;
+
+  g_return_if_fail (drawable != NULL);
+  g_return_if_fail (image != NULL);
+  g_return_if_fail (gc != NULL);
+
+  drawable_private = (GdkWindowPrivate*) drawable;
+  if (drawable_private->destroyed)
+    return;
+  image_private = (GdkImagePrivate*) image;
+  gc_private = (GdkGCPrivate*) gc;
+
+  /* The image can in fact be "shared", so don't test */
+
+  hdc = gdk_gc_predraw (drawable_private, gc_private);
+  colormap_private = (GdkColormapPrivate *) drawable_private->colormap;
+  if (colormap_private && colormap_private->xcolormap->rc_palette)
+    {
+      DIBSECTION ds;
+      static struct {
+       BITMAPINFOHEADER bmiHeader;
+       WORD bmiIndices[256];
+      } bmi;
+      static gboolean bmi_inited = FALSE;
+      int i;
+
+      if (!bmi_inited)
+       {
+         for (i = 0; i < 256; i++)
+           bmi.bmiIndices[i] = i;
+         bmi_inited = TRUE;
+       }
+
+      if (GetObject (image_private->ximage, sizeof (DIBSECTION),
+                    &ds) != sizeof (DIBSECTION))
+       {
+         g_warning ("gdk_image_put_normal: GetObject failed");
+       }
+#if 0
+      g_print("xdest = %d, ydest = %d, xsrc = %d, ysrc = %d, width = %d, height = %d\n",
+             xdest, ydest, xsrc, ysrc, width, height);
+      g_print("bmWidth = %d, bmHeight = %d, bmBitsPixel = %d, bmBits = %p\n",
+             ds.dsBm.bmWidth, ds.dsBm.bmHeight, ds.dsBm.bmBitsPixel, ds.dsBm.bmBits);
+      g_print("biWidth = %d, biHeight = %d, biBitCount = %d, biClrUsed = %d\n",
+             ds.dsBmih.biWidth, ds.dsBmih.biHeight, ds.dsBmih.biBitCount, ds.dsBmih.biClrUsed);
+#endif
+      bmi.bmiHeader = ds.dsBmih;
+      /* I have spent hours on getting the parameters to
+       * SetDIBitsToDevice right. I wonder what drugs the guys in
+       * Redmond were on when they designed this API.
+       */
+      if (SetDIBitsToDevice (hdc,
+                            xdest, ydest,
+                            width, height,
+                            xsrc, (-ds.dsBmih.biHeight)-height-ysrc,
+                            0, -ds.dsBmih.biHeight,
+                            ds.dsBm.bmBits,
+                            (CONST BITMAPINFO *) &bmi,
+                            DIB_PAL_COLORS) == 0)
+       g_warning ("SetDIBitsToDevice failed");
+    }
+  else
+    {
+      HDC memdc;
+      HGDIOBJ oldbitmap;
+
+      if ((memdc = CreateCompatibleDC (hdc)) == NULL)
+       {
+         g_warning ("gdk_image_put_normal: CreateCompatibleDC failed");
+         gdk_gc_postdraw (drawable_private, gc_private);
+         return;
+       }
+
+      if ((oldbitmap = SelectObject (memdc, image_private->ximage)) == NULL)
+       {
+         g_warning ("gdk_image_put_normal: SelectObject #1 failed");
+         gdk_gc_postdraw (drawable_private, gc_private);
+         return;
+       }
+      if (!BitBlt (hdc, xdest, ydest, width, height,
+                  memdc, xsrc, ysrc, SRCCOPY))
+       g_warning ("gdk_image_put_normal: BitBlt failed");
+
+      if (SelectObject (memdc, oldbitmap) == NULL)
+       g_warning ("gdk_image_put_normal: SelectObject #2 failed");
+
+      if (!DeleteDC (memdc))
+       g_warning ("gdk_image_put_normal: DeleteDC failed");
+    }
+  gdk_gc_postdraw (drawable_private, gc_private);
+}
diff --git a/gdk/win32/gdkinput-win32.c b/gdk/win32/gdkinput-win32.c
new file mode 100644 (file)
index 0000000..fcd3c10
--- /dev/null
@@ -0,0 +1,1524 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1999 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "gdk.h"
+#include "gdkx.h"
+#include "gdkprivate.h"
+
+#include "gdkinput.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+/* If USE_SYSCONTEXT is on, we open the Wintab device (hmm, what if
+ * there are several?) as a system pointing device, i.e. it controls
+ * the normal Windows cursor. This seems much more natural.
+ */
+#define USE_SYSCONTEXT 1       /* The code for the other choice is not
+                                * good at all.
+                                */
+
+#define TWOPI (2.*M_PI)
+
+#define PING() g_print("%s: %d\n",__FILE__,__LINE__)
+
+/* Forward declarations */
+
+static gint gdk_input_win32_set_mode (guint32      deviceid,
+                                     GdkInputMode mode);
+static void gdk_input_win32_get_pointer (GdkWindow       *window,
+                                        guint32            deviceid,
+                                        gdouble         *x,
+                                        gdouble         *y,
+                                        gdouble         *pressure,
+                                        gdouble         *xtilt,
+                                        gdouble         *ytilt,
+                                        GdkModifierType *mask);
+static void gdk_input_none_get_pointer (GdkWindow       *window,
+                                       guint32          deviceid,
+                                       gdouble         *x,
+                                       gdouble         *y,
+                                       gdouble         *pressure,
+                                       gdouble         *xtilt,
+                                       gdouble         *ytilt,
+                                       GdkModifierType *mask);
+static gint gdk_input_win32_grab_pointer (GdkWindow *     window,
+                                         gint            owner_events,
+                                         GdkEventMask    event_mask,
+                                         GdkWindow      *confine_to,
+                                         guint32         time);
+static void gdk_input_win32_ungrab_pointer (guint32 time);
+static void gdk_input_win32_configure_event (GdkEventConfigure *event, 
+                                            GdkWindow         *window);
+static void gdk_input_win32_enter_event (GdkEventCrossing  *xevent, 
+                                        GdkWindow         *window);
+static gint gdk_input_win32_other_event (GdkEvent  *event, 
+                                        MSG       *xevent);
+static gint gdk_input_win32_enable_window (GdkWindow        *window,
+                                          GdkDevicePrivate *gdkdev);
+static gint gdk_input_win32_disable_window (GdkWindow        *window,
+                                           GdkDevicePrivate *gdkdev);
+
+static GdkInputWindow *gdk_input_window_find (GdkWindow *window);
+static GdkInputWindow *gdk_input_window_find_within (GdkWindow *window);
+static GdkDevicePrivate *gdk_input_find_device (guint32 deviceid);
+static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx,
+                                                     UINT id);
+
+/* Local variables */
+
+static GList     *gdk_input_devices;
+static GList     *gdk_input_windows;
+static GList     *wintab_contexts;
+
+static gint gdk_input_root_width;
+static gint gdk_input_root_height;
+
+static GdkWindow *wintab_window;
+
+static guint32 last_moved_cursor_id;
+
+static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y };
+
+static GdkDeviceInfo gdk_input_core_info =
+{
+  GDK_CORE_POINTER,
+  "Core Pointer",
+  GDK_SOURCE_MOUSE,
+  GDK_MODE_SCREEN,
+  TRUE,
+  2,
+  gdk_input_core_axes
+};
+
+/* Global variables  */
+
+GdkInputVTable    gdk_input_vtable;
+gint              gdk_input_ignore_core;
+gint             gdk_input_ignore_wintab = FALSE;
+
+#if 0
+
+static void
+print_lc(LOGCONTEXT *lc)
+{
+  g_print ("lcName = %s\n", lc->lcName);
+  g_print ("lcOptions =");
+  if (lc->lcOptions & CXO_SYSTEM) g_print (" CXO_SYSTEM");
+  if (lc->lcOptions & CXO_PEN) g_print (" CXO_PEN");
+  if (lc->lcOptions & CXO_MESSAGES) g_print (" CXO_MESSAGES");
+  if (lc->lcOptions & CXO_MARGIN) g_print (" CXO_MARGIN");
+  if (lc->lcOptions & CXO_MGNINSIDE) g_print (" CXO_MGNINSIDE");
+  if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES");
+  if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES");
+  g_print ("\n");
+  g_print ("lcStatus =");
+  if (lc->lcStatus & CXS_DISABLED) g_print (" CXS_DISABLED");
+  if (lc->lcStatus & CXS_OBSCURED) g_print (" CXS_OBSCURED");
+  if (lc->lcStatus & CXS_ONTOP) g_print (" CXS_ONTOP");
+  g_print ("\n");
+  g_print ("lcLocks =");
+  if (lc->lcLocks & CXL_INSIZE) g_print (" CXL_INSIZE");
+  if (lc->lcLocks & CXL_INASPECT) g_print (" CXL_INASPECT");
+  if (lc->lcLocks & CXL_SENSITIVITY) g_print (" CXL_SENSITIVITY");
+  if (lc->lcLocks & CXL_MARGIN) g_print (" CXL_MARGIN");
+  g_print ("\n");
+  g_print ("lcMsgBase = %#x, lcDevice = %#x, lcPktRate = %d\n",
+         lc->lcMsgBase, lc->lcDevice, lc->lcPktRate);
+  g_print ("lcPktData =");
+  if (lc->lcPktData & PK_CONTEXT) g_print (" PK_CONTEXT");
+  if (lc->lcPktData & PK_STATUS) g_print (" PK_STATUS");
+  if (lc->lcPktData & PK_TIME) g_print (" PK_TIME");
+  if (lc->lcPktData & PK_CHANGED) g_print (" PK_CHANGED");
+  if (lc->lcPktData & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
+  if (lc->lcPktData & PK_CURSOR) g_print (" PK_CURSOR");
+  if (lc->lcPktData & PK_BUTTONS) g_print (" PK_BUTTONS");
+  if (lc->lcPktData & PK_X) g_print (" PK_X");
+  if (lc->lcPktData & PK_Y) g_print (" PK_Y");
+  if (lc->lcPktData & PK_Z) g_print (" PK_Z");
+  if (lc->lcPktData & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
+  if (lc->lcPktData & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
+  if (lc->lcPktData & PK_ORIENTATION) g_print (" PK_ORIENTATION");
+  if (lc->lcPktData & PK_ROTATION) g_print (" PK_ROTATION");
+  g_print ("\n");
+  g_print ("lcPktMode =");
+  if (lc->lcPktMode & PK_CONTEXT) g_print (" PK_CONTEXT");
+  if (lc->lcPktMode & PK_STATUS) g_print (" PK_STATUS");
+  if (lc->lcPktMode & PK_TIME) g_print (" PK_TIME");
+  if (lc->lcPktMode & PK_CHANGED) g_print (" PK_CHANGED");
+  if (lc->lcPktMode & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
+  if (lc->lcPktMode & PK_CURSOR) g_print (" PK_CURSOR");
+  if (lc->lcPktMode & PK_BUTTONS) g_print (" PK_BUTTONS");
+  if (lc->lcPktMode & PK_X) g_print (" PK_X");
+  if (lc->lcPktMode & PK_Y) g_print (" PK_Y");
+  if (lc->lcPktMode & PK_Z) g_print (" PK_Z");
+  if (lc->lcPktMode & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
+  if (lc->lcPktMode & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
+  if (lc->lcPktMode & PK_ORIENTATION) g_print (" PK_ORIENTATION");
+  if (lc->lcPktMode & PK_ROTATION) g_print (" PK_ROTATION");
+  g_print ("\n");
+  g_print ("lcMoveMask =");
+  if (lc->lcMoveMask & PK_CONTEXT) g_print (" PK_CONTEXT");
+  if (lc->lcMoveMask & PK_STATUS) g_print (" PK_STATUS");
+  if (lc->lcMoveMask & PK_TIME) g_print (" PK_TIME");
+  if (lc->lcMoveMask & PK_CHANGED) g_print (" PK_CHANGED");
+  if (lc->lcMoveMask & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
+  if (lc->lcMoveMask & PK_CURSOR) g_print (" PK_CURSOR");
+  if (lc->lcMoveMask & PK_BUTTONS) g_print (" PK_BUTTONS");
+  if (lc->lcMoveMask & PK_X) g_print (" PK_X");
+  if (lc->lcMoveMask & PK_Y) g_print (" PK_Y");
+  if (lc->lcMoveMask & PK_Z) g_print (" PK_Z");
+  if (lc->lcMoveMask & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
+  if (lc->lcMoveMask & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
+  if (lc->lcMoveMask & PK_ORIENTATION) g_print (" PK_ORIENTATION");
+  if (lc->lcMoveMask & PK_ROTATION) g_print (" PK_ROTATION");
+  g_print ("\n");
+  g_print ("lcBtnDnMask = %#x, lcBtnUpMask = %#x\n",
+         lc->lcBtnDnMask, lc->lcBtnUpMask);
+  g_print ("lcInOrgX = %d, lcInOrgY = %d, lcInOrgZ = %d\n",
+         lc->lcInOrgX, lc->lcInOrgY, lc->lcInOrgZ);
+  g_print ("lcInExtX = %d, lcInExtY = %d, lcInExtZ = %d\n",
+         lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ);
+  g_print ("lcOutOrgX = %d, lcOutOrgY = %d, lcOutOrgZ = %d\n",
+         lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ);
+  g_print ("lcOutExtX = %d, lcOutExtY = %d, lcOutExtZ = %d\n",
+         lc->lcOutExtX, lc->lcOutExtY, lc->lcOutExtZ);
+  g_print ("lcSensX = %g, lcSensY = %g, lcSensZ = %g\n",
+         lc->lcSensX / 65536., lc->lcSensY / 65536., lc->lcSensZ / 65536.);
+  g_print ("lcSysMode = %d\n", lc->lcSysMode);
+  g_print ("lcSysOrgX = %d, lcSysOrgY = %d\n",
+         lc->lcSysOrgX, lc->lcSysOrgY);
+  g_print ("lcSysExtX = %d, lcSysExtY = %d\n",
+         lc->lcSysExtX, lc->lcSysExtY);
+  g_print ("lcSysSensX = %g, lcSysSensY = %g\n",
+         lc->lcSysSensX / 65536., lc->lcSysSensY / 65536.);
+}
+
+#endif
+
+void 
+gdk_input_init (void)
+{
+  GdkDevicePrivate *gdkdev;
+  GdkWindowPrivate *window_private;
+  GdkWindowAttr wa;
+  WORD specversion;
+  LOGCONTEXT defcontext;
+  HCTX *hctx;
+  UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware;
+  AXIS axis_x, axis_y, axis_npressure, axis_orientation[3];
+  int i, j, k;
+  char devname[100], csrname[100];
+  guint32 deviceid_counter = 0;
+
+  gdk_input_devices = NULL;
+  wintab_contexts = NULL;
+
+  if (!gdk_input_ignore_wintab &&
+      WTInfo (0, 0, NULL))
+    {
+      WTInfo (WTI_INTERFACE, IFC_SPECVERSION, &specversion);
+
+#if USE_SYSCONTEXT
+      WTInfo (WTI_DEFSYSCTX, 0, &defcontext);
+#else
+      WTInfo (WTI_DEFCONTEXT, 0, &defcontext);
+#endif
+#if 0
+      g_print("DEFCONTEXT:\n"); print_lc(&defcontext);
+#endif
+      WTInfo (WTI_INTERFACE, IFC_NDEVICES, &ndevices);
+      WTInfo (WTI_INTERFACE, IFC_NCURSORS, &ncursors);
+
+      /* Create a dummy window to receive wintab events */
+      wa.wclass = GDK_INPUT_OUTPUT;
+      wa.event_mask = GDK_ALL_EVENTS_MASK;
+      wa.width = 2;
+      wa.height = 2;
+      wa.x = -100;
+      wa.y = -100;
+      wa.window_type = GDK_WINDOW_TOPLEVEL;
+      if ((wintab_window = gdk_window_new (NULL, &wa, GDK_WA_X|GDK_WA_Y)) == NULL)
+       {
+         g_warning ("gdk_input_init: gdk_window_new failed");
+         return;
+       }
+      gdk_window_ref (wintab_window);
+      window_private = (GdkWindowPrivate *) wintab_window;
+      
+      for (i = 0; i < ndevices; i++)
+       {
+         LOGCONTEXT lc;
+
+         WTInfo (WTI_DEVICES + i, DVC_NAME, devname);
+      
+         WTInfo (WTI_DEVICES + i, DVC_NCSRTYPES, &ncsrtypes);
+         WTInfo (WTI_DEVICES + i, DVC_FIRSTCSR, &firstcsr);
+         WTInfo (WTI_DEVICES + i, DVC_HARDWARE, &hardware);
+         WTInfo (WTI_DEVICES + i, DVC_X, &axis_x);
+         WTInfo (WTI_DEVICES + i, DVC_Y, &axis_y);
+         WTInfo (WTI_DEVICES + i, DVC_NPRESSURE, &axis_npressure);
+         WTInfo (WTI_DEVICES + i, DVC_ORIENTATION, axis_orientation);
+
+         if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1)
+           {
+             WTInfo (WTI_DDCTXS + i, CTX_NAME, lc.lcName);
+             WTInfo (WTI_DDCTXS + i, CTX_OPTIONS, &lc.lcOptions);
+             lc.lcOptions |= CXO_MESSAGES;
+             lc.lcStatus = 0;
+             WTInfo (WTI_DDCTXS + i, CTX_LOCKS, &lc.lcLocks);
+             lc.lcMsgBase = WT_DEFBASE;
+             lc.lcDevice = i;
+             lc.lcPktRate = 20;
+             lc.lcPktData = PACKETDATA;
+             lc.lcPktMode = PK_BUTTONS; /* We want buttons in relative mode */
+             lc.lcMoveMask = PACKETDATA;
+             lc.lcBtnDnMask = lc.lcBtnUpMask = ~0;
+             WTInfo (WTI_DDCTXS + i, CTX_INORGX, &lc.lcInOrgX);
+             WTInfo (WTI_DDCTXS + i, CTX_INORGY, &lc.lcInOrgY);
+             WTInfo (WTI_DDCTXS + i, CTX_INORGZ, &lc.lcInOrgZ);
+             WTInfo (WTI_DDCTXS + i, CTX_INEXTX, &lc.lcInExtX);
+             WTInfo (WTI_DDCTXS + i, CTX_INEXTY, &lc.lcInExtY);
+             WTInfo (WTI_DDCTXS + i, CTX_INEXTZ, &lc.lcInExtZ);
+             lc.lcOutOrgX = axis_x.axMin;
+             lc.lcOutOrgY = axis_y.axMin;
+             lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
+             lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
+             lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
+             WTInfo (WTI_DDCTXS + i, CTX_SENSX, &lc.lcSensX);
+             WTInfo (WTI_DDCTXS + i, CTX_SENSY, &lc.lcSensY);
+             WTInfo (WTI_DDCTXS + i, CTX_SENSZ, &lc.lcSensZ);
+             WTInfo (WTI_DDCTXS + i, CTX_SYSMODE, &lc.lcSysMode);
+             lc.lcSysOrgX = lc.lcSysOrgY = 0;
+             WTInfo (WTI_DDCTXS + i, CTX_SYSEXTX, &lc.lcSysExtX);
+             WTInfo (WTI_DDCTXS + i, CTX_SYSEXTY, &lc.lcSysExtY);
+             WTInfo (WTI_DDCTXS + i, CTX_SYSSENSX, &lc.lcSysSensX);
+             WTInfo (WTI_DDCTXS + i, CTX_SYSSENSY, &lc.lcSysSensY);
+           }
+         else
+           {
+             lc = defcontext;
+             lc.lcOptions |= CXO_MESSAGES;
+             lc.lcMsgBase = WT_DEFBASE;
+             lc.lcPktRate = 20; /* Slow down the packets a bit */
+             lc.lcPktData = PACKETDATA;
+             lc.lcPktMode = PACKETMODE;
+             lc.lcMoveMask = PACKETDATA;
+             lc.lcBtnUpMask = lc.lcBtnDnMask = ~0;
+#if 0
+             lc.lcOutExtY = -lc.lcOutExtY; /* Y grows downward */
+#else
+             lc.lcOutOrgX = axis_x.axMin;
+             lc.lcOutOrgY = axis_y.axMin;
+             lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
+             lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
+             lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
+#endif
+           }
+#if 0
+         g_print("context for device %d:\n", i); print_lc(&lc);
+#endif
+         hctx = g_new (HCTX, 1);
+          if ((*hctx = WTOpen (window_private->xwindow, &lc, TRUE)) == NULL)
+           {
+             g_warning ("gdk_input_init: WTOpen failed");
+             return;
+           }
+         GDK_NOTE (MISC, g_print ("gdk_input_init: opened Wintab device %d %#x\n",
+                                  i, *hctx));
+
+         wintab_contexts = g_list_append (wintab_contexts, hctx);
+#if 0
+         WTEnable (*hctx, TRUE);
+#endif
+         WTOverlap (*hctx, TRUE);
+
+#if 0
+         g_print("context for device %d after WTOpen:\n", i); print_lc(&lc);
+#endif
+         for (j = firstcsr; j < firstcsr + ncsrtypes; j++)
+           {
+             gdkdev = g_new (GdkDevicePrivate, 1);
+             WTInfo (WTI_CURSORS + j, CSR_NAME, csrname);
+             gdkdev->info.name = g_strconcat (devname, " ", csrname, NULL);
+             gdkdev->info.deviceid = deviceid_counter++;
+             gdkdev->info.source = GDK_SOURCE_PEN;
+             gdkdev->info.mode = GDK_MODE_SCREEN;
+#if USE_SYSCONTEXT
+             gdkdev->info.has_cursor = TRUE;
+#else
+             gdkdev->info.has_cursor = FALSE;
+#endif
+             gdkdev->hctx = *hctx;
+             gdkdev->cursor = j;
+             WTInfo (WTI_CURSORS + j, CSR_PKTDATA, &gdkdev->pktdata);
+             gdkdev->info.num_axes = 0;
+             if (gdkdev->pktdata & PK_X)
+               gdkdev->info.num_axes++;
+             if (gdkdev->pktdata & PK_Y)
+               gdkdev->info.num_axes++;
+             if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
+               gdkdev->info.num_axes++;
+             if (gdkdev->pktdata & PK_ORIENTATION)
+               gdkdev->info.num_axes += 2; /* x and y tilt */
+             WTInfo (WTI_CURSORS + j, CSR_NPBTNMARKS, &gdkdev->npbtnmarks);
+             gdkdev->axes = g_new (GdkAxisInfo, gdkdev->info.num_axes);
+             gdkdev->info.axes = g_new (GdkAxisUse, gdkdev->info.num_axes);
+             gdkdev->last_axis_data = g_new (gint, gdkdev->info.num_axes);
+             
+             for (k = 0; k < GDK_AXIS_LAST; k++)
+               gdkdev->axis_for_use[k] = -1;
+
+             k = 0;
+             if (gdkdev->pktdata & PK_X)
+               {
+                 gdkdev->axes[k].xresolution =
+                   gdkdev->axes[k].resolution = axis_x.axResolution / 65535.;
+                 gdkdev->axes[k].xmin_value =
+                   gdkdev->axes[k].min_value = axis_x.axMin;
+                 gdkdev->axes[k].xmax_value =
+                   gdkdev->axes[k].max_value = axis_x.axMax;
+                 gdkdev->info.axes[k] = GDK_AXIS_X;
+                 gdkdev->axis_for_use[GDK_AXIS_X] = k;
+                 k++;
+               }
+             if (gdkdev->pktdata & PK_Y)
+               {
+                 gdkdev->axes[k].xresolution =
+                   gdkdev->axes[k].resolution = axis_y.axResolution / 65535.;
+                 gdkdev->axes[k].xmin_value =
+                   gdkdev->axes[k].min_value = axis_y.axMin;
+                 gdkdev->axes[k].xmax_value =
+                   gdkdev->axes[k].max_value = axis_y.axMax;
+                 gdkdev->info.axes[k] = GDK_AXIS_Y;
+                 gdkdev->axis_for_use[GDK_AXIS_Y] = k;
+                 k++;
+               }
+             if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
+               {
+                 gdkdev->axes[k].xresolution =
+                   gdkdev->axes[k].resolution = axis_npressure.axResolution / 65535.;
+                 gdkdev->axes[k].xmin_value =
+                   gdkdev->axes[k].min_value = axis_npressure.axMin;
+                 gdkdev->axes[k].xmax_value =
+                   gdkdev->axes[k].max_value = axis_npressure.axMax;
+                 gdkdev->info.axes[k] = GDK_AXIS_PRESSURE;
+                 gdkdev->axis_for_use[GDK_AXIS_PRESSURE] = k;
+                 k++;
+               }
+             if (gdkdev->pktdata & PK_ORIENTATION)
+               {
+                 GdkAxisUse axis;
+
+                 gdkdev->orientation_axes[0] = axis_orientation[0];
+                 gdkdev->orientation_axes[1] = axis_orientation[1];
+                 for (axis = GDK_AXIS_XTILT; axis <= GDK_AXIS_YTILT; axis++)
+                   {
+                     gdkdev->axes[k].xresolution =
+                       gdkdev->axes[k].resolution = 1000;
+                     gdkdev->axes[k].xmin_value =
+                       gdkdev->axes[k].min_value = -1000;
+                     gdkdev->axes[k].xmax_value =
+                       gdkdev->axes[k].max_value = 1000;
+                     gdkdev->info.axes[k] = axis;
+                     gdkdev->axis_for_use[axis] = k;
+                     k++;
+                   }
+               }
+             gdkdev->info.num_keys = 0;
+             gdkdev->info.keys = NULL;
+             GDK_NOTE (EVENTS,
+                       g_print ("gdk_input_init: device: %d axes: %d\n",
+                                gdkdev->info.deviceid,
+                                gdkdev->info.num_axes));
+             gdk_input_devices = g_list_append (gdk_input_devices,
+                                                gdkdev);
+           }
+       }
+      gdk_input_vtable.set_mode           = gdk_input_win32_set_mode;
+      gdk_input_vtable.set_axes           = NULL;
+      gdk_input_vtable.set_key            = NULL;
+      gdk_input_vtable.motion_events      = NULL;
+      gdk_input_vtable.get_pointer       = gdk_input_win32_get_pointer;
+      gdk_input_vtable.grab_pointer      = gdk_input_win32_grab_pointer;
+      gdk_input_vtable.ungrab_pointer     = gdk_input_win32_ungrab_pointer;
+      gdk_input_vtable.configure_event    = gdk_input_win32_configure_event;
+      gdk_input_vtable.enter_event        = gdk_input_win32_enter_event;
+      gdk_input_vtable.other_event        = gdk_input_win32_other_event;
+      gdk_input_vtable.enable_window      = gdk_input_win32_enable_window;
+      gdk_input_vtable.disable_window     = gdk_input_win32_disable_window;
+
+      gdk_input_root_width = gdk_screen_width ();
+      gdk_input_root_height = gdk_screen_height ();
+      gdk_input_ignore_core = FALSE;
+    }
+  else
+    {
+      gdk_input_vtable.set_mode           = NULL;
+      gdk_input_vtable.set_axes           = NULL;
+      gdk_input_vtable.set_key            = NULL;
+      gdk_input_vtable.motion_events      = NULL;
+      gdk_input_vtable.get_pointer       = gdk_input_none_get_pointer;
+      gdk_input_vtable.grab_pointer      = NULL;
+      gdk_input_vtable.ungrab_pointer     = NULL;
+      gdk_input_vtable.configure_event    = NULL;
+      gdk_input_vtable.enter_event        = NULL;
+      gdk_input_vtable.other_event        = NULL;
+      gdk_input_vtable.enable_window      = NULL;
+      gdk_input_vtable.disable_window     = NULL;
+      gdk_input_ignore_core = FALSE;
+    }
+  
+  gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info);
+}
+
+static void
+gdk_input_get_root_relative_geometry (HWND w,
+                                     int  *x_ret,
+                                     int  *y_ret)
+{
+  RECT rect;
+
+  GetWindowRect (w, &rect);
+
+  if (x_ret)
+    *x_ret = rect.left;
+  if (y_ret)
+    *y_ret = rect.top;
+}
+
+static void
+gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
+                                GdkInputWindow   *input_window,
+                                gint             *axis_data,
+                                gdouble          *x,
+                                gdouble          *y,
+                                gdouble          *pressure,
+                                gdouble          *xtilt,
+                                gdouble          *ytilt)
+{
+  GdkWindowPrivate *window_private;
+  gint x_axis, y_axis, pressure_axis, xtilt_axis, ytilt_axis;
+  gdouble device_width, device_height;
+  gdouble x_offset, y_offset, x_scale, y_scale;
+
+  window_private = (GdkWindowPrivate *) input_window->window;
+
+  x_axis = gdkdev->axis_for_use[GDK_AXIS_X];
+  y_axis = gdkdev->axis_for_use[GDK_AXIS_Y];
+  pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE];
+  xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT];
+  ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT];
+
+  device_width = gdkdev->axes[x_axis].max_value - 
+                  gdkdev->axes[x_axis].min_value;
+  device_height = gdkdev->axes[y_axis].max_value - 
+                    gdkdev->axes[y_axis].min_value;
+
+  if (gdkdev->info.mode == GDK_MODE_SCREEN) 
+    {
+      x_scale = gdk_input_root_width / device_width;
+      y_scale = gdk_input_root_height / device_height;
+
+      x_offset = -input_window->root_x;
+      y_offset = -input_window->root_y;
+    }
+  else                         /* GDK_MODE_WINDOW */
+    {
+      double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) /
+       (device_width*gdkdev->axes[x_axis].resolution);
+
+      if (device_aspect * window_private->width >= window_private->height)
+       {
+         /* device taller than window */
+         x_scale = window_private->width / device_width;
+         y_scale = (x_scale * gdkdev->axes[x_axis].resolution)
+           / gdkdev->axes[y_axis].resolution;
+
+         x_offset = 0;
+         y_offset = -(device_height * y_scale - 
+                              window_private->height)/2;
+       }
+      else
+       {
+         /* window taller than device */
+         y_scale = window_private->height / device_height;
+         x_scale = (y_scale * gdkdev->axes[y_axis].resolution)
+           / gdkdev->axes[x_axis].resolution;
+
+         y_offset = 0;
+         x_offset = -(device_width * x_scale - window_private->width)/2;
+       }
+    }
+  
+  if (x)
+    *x = x_offset + x_scale*axis_data[x_axis];
+  if (y)
+    *y = y_offset + y_scale*axis_data[y_axis];
+
+  if (pressure)
+    {
+      if (pressure_axis != -1)
+       *pressure = ((double)axis_data[pressure_axis] 
+                    - gdkdev->axes[pressure_axis].min_value) 
+         / (gdkdev->axes[pressure_axis].max_value 
+            - gdkdev->axes[pressure_axis].min_value);
+      else
+       *pressure = 0.5;
+    }
+
+  if (xtilt)
+    {
+      if (xtilt_axis != -1)
+       {
+         *xtilt = 2. * (double)(axis_data[xtilt_axis] - 
+                                (gdkdev->axes[xtilt_axis].min_value +
+                                 gdkdev->axes[xtilt_axis].max_value)/2) /
+           (gdkdev->axes[xtilt_axis].max_value -
+            gdkdev->axes[xtilt_axis].min_value);
+       }
+      else
+       *xtilt = 0;
+    }
+  
+  if (ytilt)
+    {
+      if (ytilt_axis != -1)
+       {
+         *ytilt = 2. * (double)(axis_data[ytilt_axis] - 
+                                (gdkdev->axes[ytilt_axis].min_value +
+                                 gdkdev->axes[ytilt_axis].max_value)/2) /
+           (gdkdev->axes[ytilt_axis].max_value -
+            gdkdev->axes[ytilt_axis].min_value);
+       }
+      else
+       *ytilt = 0;
+    }
+}
+
+gint
+gdk_input_set_mode (guint32      deviceid,
+                   GdkInputMode mode)
+{
+  if (deviceid == GDK_CORE_POINTER)
+    return FALSE;
+
+  if (gdk_input_vtable.set_mode)
+    return gdk_input_vtable.set_mode (deviceid, mode);
+  else
+    return FALSE;
+}
+
+void
+gdk_input_set_axes (guint32     deviceid,
+                   GdkAxisUse *axes)
+{
+  int i;
+  GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid);
+  g_return_if_fail (gdkdev != NULL);
+
+  if (deviceid == GDK_CORE_POINTER)
+    return;
+
+  for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++)
+    {
+      gdkdev->axis_for_use[i] = -1;
+    }
+
+  for (i = 0; i < gdkdev->info.num_axes; i++)
+    {
+      gdkdev->info.axes[i] = axes[i];
+      gdkdev->axis_for_use[axes[i]] = i;
+    }
+}
+
+static void 
+gdk_input_win32_get_pointer (GdkWindow       *window,
+                            guint32          deviceid,
+                            gdouble         *x,
+                            gdouble         *y,
+                            gdouble         *pressure,
+                            gdouble         *xtilt,
+                            gdouble         *ytilt,
+                            GdkModifierType *mask)
+{
+  GdkDevicePrivate *gdkdev;
+  GdkInputWindow *input_window;
+  gint x_int, y_int;
+  gint i;
+
+  if (deviceid == GDK_CORE_POINTER)
+    {
+      gdk_window_get_pointer (window, &x_int, &y_int, mask);
+      if (x)
+       *x = x_int;
+      if (y)
+       *y = y_int;
+      if (pressure)
+       *pressure = 0.5;
+      if (xtilt)
+       *xtilt = 0;
+      if (ytilt)
+       *ytilt = 0;
+    }
+  else
+    {
+      if (mask)
+       gdk_window_get_pointer (window, NULL, NULL, mask);
+      
+      gdkdev = gdk_input_find_device (deviceid);
+      g_return_if_fail (gdkdev != NULL);
+
+      input_window = gdk_input_window_find (window);
+      g_return_if_fail (input_window != NULL);
+
+      gdk_input_translate_coordinates (gdkdev, input_window,
+                                      gdkdev->last_axis_data,
+                                      x, y, pressure,
+                                      xtilt, ytilt);
+      if (mask)
+       {
+         *mask &= 0xFF;
+         *mask |= ((gdkdev->last_buttons & 0x1F) << 8);
+       }
+    }
+}
+
+static void
+gdk_input_none_get_pointer (GdkWindow       *window,
+                           guint32          deviceid,
+                           gdouble         *x,
+                           gdouble         *y,
+                           gdouble         *pressure,
+                           gdouble         *xtilt,
+                           gdouble         *ytilt,
+                           GdkModifierType *mask)
+{
+  gint x_int, y_int;
+
+  gdk_window_get_pointer (window, &x_int, &y_int, mask);
+
+  if (x)
+    *x = x_int;
+  if (y)
+    *y = y_int;
+  if (pressure)
+    *pressure = 0.5;
+  if (xtilt)
+    *xtilt = 0;
+  if (ytilt)
+    *ytilt = 0;
+}
+
+static gint
+gdk_input_win32_set_mode (guint32      deviceid,
+                         GdkInputMode mode)
+{
+  GList *tmp_list;
+  GdkDevicePrivate *gdkdev;
+  GdkInputMode old_mode;
+  GdkInputWindow *input_window;
+
+  if (deviceid == GDK_CORE_POINTER)
+    return FALSE;
+
+  gdkdev = gdk_input_find_device (deviceid);
+  g_return_val_if_fail (gdkdev != NULL, FALSE);
+  old_mode = gdkdev->info.mode;
+
+  if (old_mode == mode)
+    return TRUE;
+
+  gdkdev->info.mode = mode;
+
+  if (mode == GDK_MODE_WINDOW)
+    {
+      gdkdev->info.has_cursor = FALSE;
+      for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
+       {
+         input_window = (GdkInputWindow *)tmp_list->data;
+         if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
+           gdk_input_win32_enable_window (input_window->window, gdkdev);
+         else
+           if (old_mode != GDK_MODE_DISABLED)
+             gdk_input_win32_disable_window (input_window->window, gdkdev);
+       }
+    }
+  else if (mode == GDK_MODE_SCREEN)
+    {
+      gdkdev->info.has_cursor = TRUE;
+      for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
+       gdk_input_win32_enable_window (((GdkInputWindow *)tmp_list->data)->window,
+                                      gdkdev);
+    }
+  else  /* mode == GDK_MODE_DISABLED */
+    {
+      for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
+       {
+         input_window = (GdkInputWindow *)tmp_list->data;
+         if (old_mode != GDK_MODE_WINDOW ||
+             input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
+           gdk_input_win32_disable_window (input_window->window, gdkdev);
+       }
+    }
+
+  return TRUE;
+}
+
+static void
+gdk_input_win32_configure_event (GdkEventConfigure *event,
+                                GdkWindow         *window)
+{
+  GdkInputWindow *input_window;
+  gint root_x, root_y;
+
+  input_window = gdk_input_window_find (window);
+  g_return_if_fail (window != NULL);
+
+  gdk_input_get_root_relative_geometry (GDK_WINDOW_XWINDOW (window),
+                                       &root_x, &root_y);
+
+  input_window->root_x = root_x;
+  input_window->root_y = root_y;
+}
+
+static void 
+gdk_input_win32_enter_event (GdkEventCrossing *event, 
+                            GdkWindow        *window)
+{
+  GdkInputWindow *input_window;
+  gint root_x, root_y;
+
+  input_window = gdk_input_window_find (window);
+  g_return_if_fail (window != NULL);
+
+  gdk_input_get_root_relative_geometry (GDK_WINDOW_XWINDOW (window),
+                                       &root_x, &root_y);
+
+  input_window->root_x = root_x;
+  input_window->root_y = root_y;
+}
+
+static void
+decode_tilt (gint   *axis_data,
+            AXIS   *axes,
+            PACKET *packet)
+{
+  /* As I don't have a tilt-sensing tablet,
+   * I cannot test this code.
+   */
+  
+  double az, el;
+
+  az = TWOPI * packet->pkOrientation.orAzimuth /
+    (axes[0].axResolution / 65536.);
+  el = TWOPI * packet->pkOrientation.orAltitude /
+    (axes[1].axResolution / 65536.);
+  
+  /* X tilt */
+  axis_data[0] = cos (az) * cos (el) * 1000;
+  /* Y tilt */
+  axis_data[1] = sin (az) * cos (el) * 1000;
+}
+
+static gint 
+gdk_input_win32_other_event (GdkEvent  *event,
+                            MSG       *xevent)
+{
+  GdkWindow *current_window;
+  GdkInputWindow *input_window;
+  GdkWindow *window;
+  GdkWindowPrivate *window_private;
+  GdkDevicePrivate *gdkdev;
+  GdkEventMask masktest;
+  POINT pt;
+  PACKET packet;
+  gint return_val;
+  gint k;
+  gint x, y;
+
+  if (event->any.window != wintab_window)
+    g_warning ("gdk_input_win32_other_event: not wintab_window?");
+
+#if USE_SYSCONTEXT
+  window = gdk_window_at_pointer (&x, &y);
+  if (window == NULL)
+    window = (GdkWindow *) &gdk_root_parent;
+
+  gdk_window_ref (window);
+
+  window_private = (GdkWindowPrivate *) window;
+
+  GDK_NOTE (EVENTS, g_print ("gdk_input_win32_other_event: window=%#x (%d,%d)\n", window_private->xwindow, x, y));
+  
+#else
+  /* ??? This code is pretty bogus */
+  current_window = gdk_window_lookup (GetActiveWindow ());
+  if (current_window == NULL)
+    return FALSE;
+  
+  input_window = gdk_input_window_find_within (current_window);
+  if (input_window == NULL)
+    return FALSE;
+#endif
+
+  if (xevent->message == WT_PACKET)
+    {
+      if (!WTPacket ((HCTX) xevent->lParam, xevent->wParam, &packet))
+       return FALSE;
+    }
+
+  switch (xevent->message)
+    {
+    case WT_PACKET:
+      if (window_private == &gdk_root_parent)
+       {
+         GDK_NOTE (EVENTS, g_print ("...is root\n"));
+         return FALSE;
+       }
+
+      if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) xevent->lParam,
+                                                packet.pkCursor)) == NULL)
+       return FALSE;
+
+      if (gdkdev->info.mode == GDK_MODE_DISABLED)
+       return FALSE;
+      
+      k = 0;
+      if (gdkdev->pktdata & PK_X)
+       gdkdev->last_axis_data[k++] = packet.pkX;
+      if (gdkdev->pktdata & PK_Y)
+       gdkdev->last_axis_data[k++] = packet.pkY;
+      if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
+       gdkdev->last_axis_data[k++] = packet.pkNormalPressure;
+      if (gdkdev->pktdata & PK_ORIENTATION)
+       {
+         decode_tilt (gdkdev->last_axis_data + k,
+                      gdkdev->orientation_axes, &packet);
+         k += 2;
+       }
+
+      g_assert (k == gdkdev->info.num_axes);
+
+      if (HIWORD (packet.pkButtons) != TBN_NONE)
+       {
+         /* Gdk buttons are numbered 1.. */
+         event->button.button = 1 + LOWORD (packet.pkButtons);
+
+         if (HIWORD (packet.pkButtons) == TBN_UP)
+           {
+             event->any.type = GDK_BUTTON_RELEASE;
+             masktest = GDK_BUTTON_RELEASE_MASK;
+             gdkdev->button_state &= ~(1 << LOWORD (packet.pkButtons));
+           }
+         else
+           {
+             event->any.type = GDK_BUTTON_PRESS;
+             masktest = GDK_BUTTON_PRESS_MASK;
+             gdkdev->button_state |= 1 << LOWORD (packet.pkButtons);
+           }
+       }
+      else
+       {
+         event->any.type = GDK_MOTION_NOTIFY;
+         masktest = GDK_POINTER_MOTION_MASK;
+         if (gdkdev->button_state & (1 << 0))
+           masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK;
+         if (gdkdev->button_state & (1 << 1))
+           masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK;
+         if (gdkdev->button_state & (1 << 2))
+           masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK;
+       }
+
+      /* Now we can check if the window wants the event, and
+       * propagate if necessary.
+       */
+    dijkstra:
+      if (!window_private->extension_events_selected
+         || !(window_private->extension_events & masktest))
+       {
+         GDK_NOTE (EVENTS, g_print ("...not selected\n"));
+
+         if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+           return FALSE;
+         
+         pt.x = x;
+         pt.y = y;
+         ClientToScreen (window_private->xwindow, &pt);
+         gdk_window_unref (window);
+         window = window_private->parent;
+         gdk_window_ref (window);
+         window_private = (GdkWindowPrivate *) window;
+         ScreenToClient (window_private->xwindow, &pt);
+         x = pt.x;
+         y = pt.y;
+         GDK_NOTE (EVENTS, g_print ("...propagating to %#x, (%d,%d)\n", window_private->xwindow, x, y));
+         goto dijkstra;
+       }
+
+      input_window = gdk_input_window_find (window);
+
+      g_assert (input_window != NULL);
+
+      if (gdkdev->info.mode == GDK_MODE_WINDOW
+         && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)
+       return FALSE;
+
+      event->any.window = window;
+
+      if (event->any.type == GDK_BUTTON_PRESS
+         || event->any.type == GDK_BUTTON_RELEASE)
+       {
+         event->button.time = xevent->time;
+         event->button.source = gdkdev->info.source;
+         last_moved_cursor_id = 
+           event->button.deviceid = gdkdev->info.deviceid;
+         
+#if 0
+#if USE_SYSCONTEXT
+         /* Buttons 1 to 3 will come in as WM_[LMR]BUTTON{DOWN,UP} */
+         if (event->button.button <= 3)
+           return FALSE;
+#endif
+#endif
+         gdk_input_translate_coordinates (gdkdev, input_window,
+                                          gdkdev->last_axis_data,
+                                          &event->button.x, &event->button.y,
+                                          &event->button.pressure,
+                                          &event->button.xtilt, 
+                                          &event->button.ytilt);
+
+         event->button.state = ((gdkdev->button_state << 8)
+                                & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+                                   | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+                                   | GDK_BUTTON5_MASK));
+         GDK_NOTE (EVENTS, g_print ("WINTAB button %s: %d %d %g,%g %g\n",
+                                    (event->button.type == GDK_BUTTON_PRESS ?
+                                     "press" : "release"),
+                                    event->button.deviceid,
+                                    event->button.button,
+                                    event->button.x, event->button.y,
+                                    event->button.pressure));
+       }
+      else
+       {
+         event->motion.time = xevent->time;
+         last_moved_cursor_id =
+           event->motion.deviceid = gdkdev->info.deviceid;
+         event->motion.is_hint = FALSE;
+         event->motion.source = gdkdev->info.source;
+
+         gdk_input_translate_coordinates (gdkdev, input_window,
+                                          gdkdev->last_axis_data,
+                                          &event->motion.x, &event->motion.y,
+                                          &event->motion.pressure,
+                                          &event->motion.xtilt, 
+                                          &event->motion.ytilt);
+
+         event->motion.state = ((gdkdev->button_state << 8)
+                                & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+                                   | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+                                   | GDK_BUTTON5_MASK));
+
+         GDK_NOTE (EVENTS, g_print ("WINTAB motion: %d %g,%g %g\n",
+                                    event->motion.deviceid,
+                                    event->motion.x, event->motion.y,
+                                    event->motion.pressure));
+
+         /* Check for missing release or press events for the normal
+          * pressure button. At least on my ArtPadII I sometimes miss a
+          * release event?
+          */
+         if ((gdkdev->pktdata & PK_NORMAL_PRESSURE
+              && (event->motion.state & GDK_BUTTON1_MASK)
+              && packet.pkNormalPressure <= MAX (0, gdkdev->npbtnmarks[0] - 2))
+             || (gdkdev->pktdata & PK_NORMAL_PRESSURE
+                 && !(event->motion.state & GDK_BUTTON1_MASK)
+                 && packet.pkNormalPressure > gdkdev->npbtnmarks[1] + 2))
+           {
+             GdkEvent *event2 = gdk_event_copy (event);
+             if (event->motion.state & GDK_BUTTON1_MASK)
+               {
+                 event2->button.type = GDK_BUTTON_RELEASE;
+                 gdkdev->button_state &= ~1;
+               }
+             else
+               {
+                 event2->button.type = GDK_BUTTON_PRESS;
+                 gdkdev->button_state |= 1;
+               }
+             event2->button.state = ((gdkdev->button_state << 8)
+                                     & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+                                        | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+                                        | GDK_BUTTON5_MASK));
+             event2->button.button = 1;
+             GDK_NOTE (EVENTS, g_print ("WINTAB synthesized button %s: %d %d %g,%g %g\n",
+                                        (event2->button.type == GDK_BUTTON_PRESS ?
+                                         "press" : "release"),
+                                        event2->button.deviceid,
+                                        event2->button.button,
+                                        event2->button.x, event2->button.y,
+                                        event2->button.pressure));
+             gdk_event_queue_append (event2);
+           }
+       }
+      return TRUE;
+
+    case WT_PROXIMITY:
+      if (LOWORD (xevent->lParam) == 0)
+       {
+         event->proximity.type = GDK_PROXIMITY_OUT;
+         gdk_input_ignore_core = FALSE;
+       }
+      else
+       {
+         event->proximity.type = GDK_PROXIMITY_IN;
+         gdk_input_ignore_core = TRUE;
+       }
+      event->proximity.time = xevent->time;
+      event->proximity.source = GDK_SOURCE_PEN;
+      event->proximity.deviceid = last_moved_cursor_id;
+
+      GDK_NOTE (EVENTS, g_print ("WINTAB proximity %s: %d\n",
+                                (event->proximity.type == GDK_PROXIMITY_IN ?
+                                 "in" : "out"),
+                                event->proximity.deviceid));
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gint
+gdk_input_win32_enable_window (GdkWindow        *window,
+                              GdkDevicePrivate *gdkdev)
+{
+  GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
+
+  window_private->extension_events_selected = TRUE;
+  return TRUE;
+}
+
+static gint
+gdk_input_win32_disable_window (GdkWindow        *window,
+                               GdkDevicePrivate *gdkdev)
+{
+  GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
+
+  window_private->extension_events_selected = FALSE;
+  return TRUE;
+}
+
+static gint
+gdk_input_win32_grab_pointer (GdkWindow    *window,
+                             gint          owner_events,
+                             GdkEventMask  event_mask,
+                             GdkWindow    *confine_to,
+                             guint32       time)
+{
+  GdkInputWindow *input_window, *new_window;
+  gboolean need_ungrab;
+  GdkDevicePrivate *gdkdev;
+  GList *tmp_list;
+  gint result;
+
+  tmp_list = gdk_input_windows;
+  new_window = NULL;
+  need_ungrab = FALSE;
+
+  while (tmp_list)
+    {
+      input_window = (GdkInputWindow *)tmp_list->data;
+
+      if (input_window->window == window)
+       new_window = input_window;
+      else if (input_window->grabbed)
+       {
+         input_window->grabbed = FALSE;
+         need_ungrab = TRUE;
+       }
+
+      tmp_list = tmp_list->next;
+    }
+
+  if (new_window)
+    {
+      new_window->grabbed = TRUE;
+      
+      tmp_list = gdk_input_devices;
+      while (tmp_list)
+       {
+         gdkdev = (GdkDevicePrivate *)tmp_list->data;
+         if (gdkdev->info.deviceid != GDK_CORE_POINTER)
+           {
+#if 0        
+             gdk_input_find_events (window, gdkdev,
+                                    event_mask,
+                                    event_classes, &num_classes);
+             result = XGrabDevice (GDK_DISPLAY(), gdkdev->xdevice,
+                                   GDK_WINDOW_XWINDOW (window),
+                                   owner_events, num_classes, event_classes,
+                                   GrabModeAsync, GrabModeAsync, time);
+             
+             /* FIXME: if failure occurs on something other than the first
+                device, things will be badly inconsistent */
+             if (result != Success)
+               return result;
+#endif
+           }
+         tmp_list = tmp_list->next;
+       }
+    }
+  else
+    { 
+      tmp_list = gdk_input_devices;
+      while (tmp_list)
+       {
+         gdkdev = (GdkDevicePrivate *)tmp_list->data;
+         if (gdkdev->info.deviceid != GDK_CORE_POINTER && 
+             ((gdkdev->button_state != 0) || need_ungrab))
+           {
+#if 0
+             XUngrabDevice (gdk_display, gdkdev->xdevice, time);
+#endif
+             gdkdev->button_state = 0;
+           }
+         
+         tmp_list = tmp_list->next;
+       }
+    }
+
+  return Success;
+      
+}
+
+static void 
+gdk_input_win32_ungrab_pointer (guint32 time)
+{
+  GdkInputWindow *input_window;
+  GdkDevicePrivate *gdkdev;
+  GList *tmp_list;
+
+  tmp_list = gdk_input_windows;
+  while (tmp_list)
+    {
+      input_window = (GdkInputWindow *)tmp_list->data;
+      if (input_window->grabbed)
+       break;
+      tmp_list = tmp_list->next;
+    }
+
+  if (tmp_list)                        /* we found a grabbed window */
+    {
+      input_window->grabbed = FALSE;
+
+      tmp_list = gdk_input_devices;
+      while (tmp_list)
+       {
+         gdkdev = (GdkDevicePrivate *)tmp_list->data;
+#if 0
+         if (gdkdev->info.deviceid != GDK_CORE_POINTER && gdkdev->xdevice)
+           XUngrabDevice (gdk_display, gdkdev->xdevice, time);
+#endif
+         tmp_list = tmp_list->next;
+       }
+    }
+}
+
+GList *
+gdk_input_list_devices (void)
+{
+  return gdk_input_devices;
+}
+
+void
+gdk_input_set_source (guint32        deviceid,
+                     GdkInputSource source)
+{
+  GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid);
+  g_return_if_fail (gdkdev != NULL);
+
+  gdkdev->info.source = source;
+}
+
+void gdk_input_set_key (guint32 deviceid,
+                       guint   index,
+                       guint   keyval,
+                       GdkModifierType modifiers)
+{
+  if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_key)
+    gdk_input_vtable.set_key (deviceid, index, keyval, modifiers);
+}
+
+GdkTimeCoord *
+gdk_input_motion_events (GdkWindow *window,
+                        guint32    deviceid,
+                        guint32    start,
+                        guint32    stop,
+                        gint      *nevents_return)
+{
+  GdkWindowPrivate *window_private;
+  GdkTimeCoord *coords;
+  int i;
+
+  g_return_val_if_fail (window != NULL, NULL);
+  window_private = (GdkWindowPrivate *) window;
+  if (window_private->destroyed)
+    return NULL;
+
+  *nevents_return = 0;
+  return NULL;         /* ??? */
+}
+
+static GdkInputWindow *
+gdk_input_window_find (GdkWindow *window)
+{
+  GList *tmp_list;
+
+  for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next)
+    if (((GdkInputWindow *)(tmp_list->data))->window == window)
+      return (GdkInputWindow *)(tmp_list->data);
+
+  return NULL;      /* Not found */
+}
+
+static GdkInputWindow *
+gdk_input_window_find_within (GdkWindow *window)
+{
+  GList *tmp_list;
+  GdkWindowPrivate *window_private;
+  GdkWindowPrivate *tmp_private;
+  GdkInputWindow *candidate = NULL;
+
+  window_private = (GdkWindowPrivate *) window;
+
+  for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next)
+    {
+      (GdkWindowPrivate *) tmp_private =
+       (GdkWindowPrivate *) (((GdkInputWindow *)(tmp_list->data))->window);
+      if (tmp_private == window_private
+         || IsChild (window_private->xwindow, tmp_private->xwindow))
+       {
+         if (candidate)
+           return NULL;                /* Multiple hits */
+         candidate = (GdkInputWindow *)(tmp_list->data);
+       }
+    }
+
+  return candidate;
+}
+
+/* FIXME: this routine currently needs to be called between creation
+   and the corresponding configure event (because it doesn't get the
+   root_relative_geometry).  This should work with
+   gtk_window_set_extension_events, but will likely fail in other
+   cases */
+
+void
+gdk_input_set_extension_events (GdkWindow       *window,
+                               gint             mask,
+                               GdkExtensionMode mode)
+{
+  GdkWindowPrivate *window_private;
+  GList *tmp_list;
+  GdkInputWindow *iw;
+
+  g_return_if_fail (window != NULL);
+  window_private = (GdkWindowPrivate *) window;
+  if (window_private->destroyed)
+    return;
+
+  if (mode == GDK_EXTENSION_EVENTS_NONE)
+    mask = 0;
+
+  if (mask != 0)
+    {
+      iw = g_new (GdkInputWindow,1);
+
+      iw->window = window;
+      iw->mode = mode;
+
+      iw->grabbed = FALSE;
+
+      gdk_input_windows = g_list_append (gdk_input_windows, iw);
+      window_private->extension_events = mask;
+
+      /* Add enter window events to the event mask */
+      gdk_window_set_events (window,
+                            gdk_window_get_events (window) | 
+                            GDK_ENTER_NOTIFY_MASK);
+    }
+  else
+    {
+      iw = gdk_input_window_find (window);
+      if (iw)
+       {
+         gdk_input_windows = g_list_remove (gdk_input_windows, iw);
+         g_free (iw);
+       }
+
+      window_private->extension_events = 0;
+    }
+
+  for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
+    {
+      GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data);
+
+      if (gdkdev->info.deviceid != GDK_CORE_POINTER)
+       {
+         if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED
+             && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL))
+           gdk_input_win32_enable_window (window, gdkdev);
+         else
+           gdk_input_win32_disable_window (window, gdkdev);
+       }
+    }
+}
+
+void
+gdk_input_window_destroy (GdkWindow *window)
+{
+  GdkInputWindow *input_window;
+
+  input_window = gdk_input_window_find (window);
+  g_return_if_fail (input_window != NULL);
+
+  gdk_input_windows = g_list_remove (gdk_input_windows,input_window);
+  g_free (input_window);
+}
+
+void
+gdk_input_exit (void)
+{
+  GList *tmp_list;
+  GdkDevicePrivate *gdkdev;
+
+  for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
+    {
+      gdkdev = (GdkDevicePrivate *)(tmp_list->data);
+      if (gdkdev->info.deviceid != GDK_CORE_POINTER)
+       {
+         gdk_input_win32_set_mode (gdkdev->info.deviceid, GDK_MODE_DISABLED);
+         g_free (gdkdev->info.name);
+         g_free (gdkdev->last_axis_data);
+         g_free (gdkdev->info.axes);
+         g_free (gdkdev->info.keys);
+         g_free (gdkdev->axes);
+         g_free (gdkdev);
+       }
+    }
+
+  g_list_free (gdk_input_devices);
+
+  for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
+    {
+      g_free (tmp_list->data);
+    }
+  g_list_free (gdk_input_windows);
+
+#if 1
+  for (tmp_list = wintab_contexts; tmp_list; tmp_list = tmp_list->next)
+    {
+      HCTX *hctx = (HCTX *) tmp_list->data;
+      BOOL result;
+
+      /* For some reason WTEnable and/or WTClose tend to crash here.
+       * Protect with __try/__except to avoid a message box.
+       */
+      __try {
+#if 0
+        WTEnable (*hctx, FALSE);
+#endif
+       result = WTClose (*hctx);
+      }
+      __except (/* GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? */
+                EXCEPTION_EXECUTE_HANDLER /*: 
+                EXCEPTION_CONTINUE_SEARCH */) {
+       result = FALSE;
+      }
+      if (!result)
+       g_warning ("gdk_input_exit: Closing Wintab context %#x failed", *hctx);
+      g_free (hctx);
+    }
+#endif
+  g_list_free (wintab_contexts);
+}
+
+static GdkDevicePrivate *
+gdk_input_find_device (guint32 id)
+{
+  GList *tmp_list = gdk_input_devices;
+  GdkDevicePrivate *gdkdev;
+
+  while (tmp_list)
+    {
+      gdkdev = (GdkDevicePrivate *) (tmp_list->data);
+      if (gdkdev->info.deviceid == id)
+       return gdkdev;
+      tmp_list = tmp_list->next;
+    }
+  return NULL;
+}
+
+static GdkDevicePrivate *
+gdk_input_find_dev_from_ctx (HCTX hctx,
+                            UINT cursor)
+{
+  GList *tmp_list = gdk_input_devices;
+  GdkDevicePrivate *gdkdev;
+
+  while (tmp_list)
+    {
+      gdkdev = (GdkDevicePrivate *) (tmp_list->data);
+      if (gdkdev->hctx == hctx && gdkdev->cursor == cursor)
+       return gdkdev;
+      tmp_list = tmp_list->next;
+    }
+  return NULL;
+}
+
+void
+gdk_input_window_get_pointer (GdkWindow       *window,
+                             guint32          deviceid,
+                             gdouble         *x,
+                             gdouble         *y,
+                             gdouble         *pressure,
+                             gdouble         *xtilt,
+                             gdouble         *ytilt,
+                             GdkModifierType *mask)
+{
+  if (gdk_input_vtable.get_pointer)
+    gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure,
+                                 xtilt, ytilt, mask);
+}
diff --git a/gdk/win32/gdkinput.c b/gdk/win32/gdkinput.c
new file mode 100644 (file)
index 0000000..fcd3c10
--- /dev/null
@@ -0,0 +1,1524 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1999 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "gdk.h"
+#include "gdkx.h"
+#include "gdkprivate.h"
+
+#include "gdkinput.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+/* If USE_SYSCONTEXT is on, we open the Wintab device (hmm, what if
+ * there are several?) as a system pointing device, i.e. it controls
+ * the normal Windows cursor. This seems much more natural.
+ */
+#define USE_SYSCONTEXT 1       /* The code for the other choice is not
+                                * good at all.
+                                */
+
+#define TWOPI (2.*M_PI)
+
+#define PING() g_print("%s: %d\n",__FILE__,__LINE__)
+
+/* Forward declarations */
+
+static gint gdk_input_win32_set_mode (guint32      deviceid,
+                                     GdkInputMode mode);
+static void gdk_input_win32_get_pointer (GdkWindow       *window,
+                                        guint32            deviceid,
+                                        gdouble         *x,
+                                        gdouble         *y,
+                                        gdouble         *pressure,
+                                        gdouble         *xtilt,
+                                        gdouble         *ytilt,
+                                        GdkModifierType *mask);
+static void gdk_input_none_get_pointer (GdkWindow       *window,
+                                       guint32          deviceid,
+                                       gdouble         *x,
+                                       gdouble         *y,
+                                       gdouble         *pressure,
+                                       gdouble         *xtilt,
+                                       gdouble         *ytilt,
+                                       GdkModifierType *mask);
+static gint gdk_input_win32_grab_pointer (GdkWindow *     window,
+                                         gint            owner_events,
+                                         GdkEventMask    event_mask,
+                                         GdkWindow      *confine_to,
+                                         guint32         time);
+static void gdk_input_win32_ungrab_pointer (guint32 time);
+static void gdk_input_win32_configure_event (GdkEventConfigure *event, 
+                                            GdkWindow         *window);
+static void gdk_input_win32_enter_event (GdkEventCrossing  *xevent, 
+                                        GdkWindow         *window);
+static gint gdk_input_win32_other_event (GdkEvent  *event, 
+                                        MSG       *xevent);
+static gint gdk_input_win32_enable_window (GdkWindow        *window,
+                                          GdkDevicePrivate *gdkdev);
+static gint gdk_input_win32_disable_window (GdkWindow        *window,
+                                           GdkDevicePrivate *gdkdev);
+
+static GdkInputWindow *gdk_input_window_find (GdkWindow *window);
+static GdkInputWindow *gdk_input_window_find_within (GdkWindow *window);
+static GdkDevicePrivate *gdk_input_find_device (guint32 deviceid);
+static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx,
+                                                     UINT id);
+
+/* Local variables */
+
+static GList     *gdk_input_devices;
+static GList     *gdk_input_windows;
+static GList     *wintab_contexts;
+
+static gint gdk_input_root_width;
+static gint gdk_input_root_height;
+
+static GdkWindow *wintab_window;
+
+static guint32 last_moved_cursor_id;
+
+static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y };
+
+static GdkDeviceInfo gdk_input_core_info =
+{
+  GDK_CORE_POINTER,
+  "Core Pointer",
+  GDK_SOURCE_MOUSE,
+  GDK_MODE_SCREEN,
+  TRUE,
+  2,
+  gdk_input_core_axes
+};
+
+/* Global variables  */
+
+GdkInputVTable    gdk_input_vtable;
+gint              gdk_input_ignore_core;
+gint             gdk_input_ignore_wintab = FALSE;
+
+#if 0
+
+static void
+print_lc(LOGCONTEXT *lc)
+{
+  g_print ("lcName = %s\n", lc->lcName);
+  g_print ("lcOptions =");
+  if (lc->lcOptions & CXO_SYSTEM) g_print (" CXO_SYSTEM");
+  if (lc->lcOptions & CXO_PEN) g_print (" CXO_PEN");
+  if (lc->lcOptions & CXO_MESSAGES) g_print (" CXO_MESSAGES");
+  if (lc->lcOptions & CXO_MARGIN) g_print (" CXO_MARGIN");
+  if (lc->lcOptions & CXO_MGNINSIDE) g_print (" CXO_MGNINSIDE");
+  if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES");
+  if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES");
+  g_print ("\n");
+  g_print ("lcStatus =");
+  if (lc->lcStatus & CXS_DISABLED) g_print (" CXS_DISABLED");
+  if (lc->lcStatus & CXS_OBSCURED) g_print (" CXS_OBSCURED");
+  if (lc->lcStatus & CXS_ONTOP) g_print (" CXS_ONTOP");
+  g_print ("\n");
+  g_print ("lcLocks =");
+  if (lc->lcLocks & CXL_INSIZE) g_print (" CXL_INSIZE");
+  if (lc->lcLocks & CXL_INASPECT) g_print (" CXL_INASPECT");
+  if (lc->lcLocks & CXL_SENSITIVITY) g_print (" CXL_SENSITIVITY");
+  if (lc->lcLocks & CXL_MARGIN) g_print (" CXL_MARGIN");
+  g_print ("\n");
+  g_print ("lcMsgBase = %#x, lcDevice = %#x, lcPktRate = %d\n",
+         lc->lcMsgBase, lc->lcDevice, lc->lcPktRate);
+  g_print ("lcPktData =");
+  if (lc->lcPktData & PK_CONTEXT) g_print (" PK_CONTEXT");
+  if (lc->lcPktData & PK_STATUS) g_print (" PK_STATUS");
+  if (lc->lcPktData & PK_TIME) g_print (" PK_TIME");
+  if (lc->lcPktData & PK_CHANGED) g_print (" PK_CHANGED");
+  if (lc->lcPktData & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
+  if (lc->lcPktData & PK_CURSOR) g_print (" PK_CURSOR");
+  if (lc->lcPktData & PK_BUTTONS) g_print (" PK_BUTTONS");
+  if (lc->lcPktData & PK_X) g_print (" PK_X");
+  if (lc->lcPktData & PK_Y) g_print (" PK_Y");
+  if (lc->lcPktData & PK_Z) g_print (" PK_Z");
+  if (lc->lcPktData & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
+  if (lc->lcPktData & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
+  if (lc->lcPktData & PK_ORIENTATION) g_print (" PK_ORIENTATION");
+  if (lc->lcPktData & PK_ROTATION) g_print (" PK_ROTATION");
+  g_print ("\n");
+  g_print ("lcPktMode =");
+  if (lc->lcPktMode & PK_CONTEXT) g_print (" PK_CONTEXT");
+  if (lc->lcPktMode & PK_STATUS) g_print (" PK_STATUS");
+  if (lc->lcPktMode & PK_TIME) g_print (" PK_TIME");
+  if (lc->lcPktMode & PK_CHANGED) g_print (" PK_CHANGED");
+  if (lc->lcPktMode & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
+  if (lc->lcPktMode & PK_CURSOR) g_print (" PK_CURSOR");
+  if (lc->lcPktMode & PK_BUTTONS) g_print (" PK_BUTTONS");
+  if (lc->lcPktMode & PK_X) g_print (" PK_X");
+  if (lc->lcPktMode & PK_Y) g_print (" PK_Y");
+  if (lc->lcPktMode & PK_Z) g_print (" PK_Z");
+  if (lc->lcPktMode & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
+  if (lc->lcPktMode & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
+  if (lc->lcPktMode & PK_ORIENTATION) g_print (" PK_ORIENTATION");
+  if (lc->lcPktMode & PK_ROTATION) g_print (" PK_ROTATION");
+  g_print ("\n");
+  g_print ("lcMoveMask =");
+  if (lc->lcMoveMask & PK_CONTEXT) g_print (" PK_CONTEXT");
+  if (lc->lcMoveMask & PK_STATUS) g_print (" PK_STATUS");
+  if (lc->lcMoveMask & PK_TIME) g_print (" PK_TIME");
+  if (lc->lcMoveMask & PK_CHANGED) g_print (" PK_CHANGED");
+  if (lc->lcMoveMask & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
+  if (lc->lcMoveMask & PK_CURSOR) g_print (" PK_CURSOR");
+  if (lc->lcMoveMask & PK_BUTTONS) g_print (" PK_BUTTONS");
+  if (lc->lcMoveMask & PK_X) g_print (" PK_X");
+  if (lc->lcMoveMask & PK_Y) g_print (" PK_Y");
+  if (lc->lcMoveMask & PK_Z) g_print (" PK_Z");
+  if (lc->lcMoveMask & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
+  if (lc->lcMoveMask & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
+  if (lc->lcMoveMask & PK_ORIENTATION) g_print (" PK_ORIENTATION");
+  if (lc->lcMoveMask & PK_ROTATION) g_print (" PK_ROTATION");
+  g_print ("\n");
+  g_print ("lcBtnDnMask = %#x, lcBtnUpMask = %#x\n",
+         lc->lcBtnDnMask, lc->lcBtnUpMask);
+  g_print ("lcInOrgX = %d, lcInOrgY = %d, lcInOrgZ = %d\n",
+         lc->lcInOrgX, lc->lcInOrgY, lc->lcInOrgZ);
+  g_print ("lcInExtX = %d, lcInExtY = %d, lcInExtZ = %d\n",
+         lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ);
+  g_print ("lcOutOrgX = %d, lcOutOrgY = %d, lcOutOrgZ = %d\n",
+         lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ);
+  g_print ("lcOutExtX = %d, lcOutExtY = %d, lcOutExtZ = %d\n",
+         lc->lcOutExtX, lc->lcOutExtY, lc->lcOutExtZ);
+  g_print ("lcSensX = %g, lcSensY = %g, lcSensZ = %g\n",
+         lc->lcSensX / 65536., lc->lcSensY / 65536., lc->lcSensZ / 65536.);
+  g_print ("lcSysMode = %d\n", lc->lcSysMode);
+  g_print ("lcSysOrgX = %d, lcSysOrgY = %d\n",
+         lc->lcSysOrgX, lc->lcSysOrgY);
+  g_print ("lcSysExtX = %d, lcSysExtY = %d\n",
+         lc->lcSysExtX, lc->lcSysExtY);
+  g_print ("lcSysSensX = %g, lcSysSensY = %g\n",
+         lc->lcSysSensX / 65536., lc->lcSysSensY / 65536.);
+}
+
+#endif
+
+void 
+gdk_input_init (void)
+{
+  GdkDevicePrivate *gdkdev;
+  GdkWindowPrivate *window_private;
+  GdkWindowAttr wa;
+  WORD specversion;
+  LOGCONTEXT defcontext;
+  HCTX *hctx;
+  UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware;
+  AXIS axis_x, axis_y, axis_npressure, axis_orientation[3];
+  int i, j, k;
+  char devname[100], csrname[100];
+  guint32 deviceid_counter = 0;
+
+  gdk_input_devices = NULL;
+  wintab_contexts = NULL;
+
+  if (!gdk_input_ignore_wintab &&
+      WTInfo (0, 0, NULL))
+    {
+      WTInfo (WTI_INTERFACE, IFC_SPECVERSION, &specversion);
+
+#if USE_SYSCONTEXT
+      WTInfo (WTI_DEFSYSCTX, 0, &defcontext);
+#else
+      WTInfo (WTI_DEFCONTEXT, 0, &defcontext);
+#endif
+#if 0
+      g_print("DEFCONTEXT:\n"); print_lc(&defcontext);
+#endif
+      WTInfo (WTI_INTERFACE, IFC_NDEVICES, &ndevices);
+      WTInfo (WTI_INTERFACE, IFC_NCURSORS, &ncursors);
+
+      /* Create a dummy window to receive wintab events */
+      wa.wclass = GDK_INPUT_OUTPUT;
+      wa.event_mask = GDK_ALL_EVENTS_MASK;
+      wa.width = 2;
+      wa.height = 2;
+      wa.x = -100;
+      wa.y = -100;
+      wa.window_type = GDK_WINDOW_TOPLEVEL;
+      if ((wintab_window = gdk_window_new (NULL, &wa, GDK_WA_X|GDK_WA_Y)) == NULL)
+       {
+         g_warning ("gdk_input_init: gdk_window_new failed");
+         return;
+       }
+      gdk_window_ref (wintab_window);
+      window_private = (GdkWindowPrivate *) wintab_window;
+      
+      for (i = 0; i < ndevices; i++)
+       {
+         LOGCONTEXT lc;
+
+         WTInfo (WTI_DEVICES + i, DVC_NAME, devname);
+      
+         WTInfo (WTI_DEVICES + i, DVC_NCSRTYPES, &ncsrtypes);
+         WTInfo (WTI_DEVICES + i, DVC_FIRSTCSR, &firstcsr);
+         WTInfo (WTI_DEVICES + i, DVC_HARDWARE, &hardware);
+         WTInfo (WTI_DEVICES + i, DVC_X, &axis_x);
+         WTInfo (WTI_DEVICES + i, DVC_Y, &axis_y);
+         WTInfo (WTI_DEVICES + i, DVC_NPRESSURE, &axis_npressure);
+         WTInfo (WTI_DEVICES + i, DVC_ORIENTATION, axis_orientation);
+
+         if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1)
+           {
+             WTInfo (WTI_DDCTXS + i, CTX_NAME, lc.lcName);
+             WTInfo (WTI_DDCTXS + i, CTX_OPTIONS, &lc.lcOptions);
+             lc.lcOptions |= CXO_MESSAGES;
+             lc.lcStatus = 0;
+             WTInfo (WTI_DDCTXS + i, CTX_LOCKS, &lc.lcLocks);
+             lc.lcMsgBase = WT_DEFBASE;
+             lc.lcDevice = i;
+             lc.lcPktRate = 20;
+             lc.lcPktData = PACKETDATA;
+             lc.lcPktMode = PK_BUTTONS; /* We want buttons in relative mode */
+             lc.lcMoveMask = PACKETDATA;
+             lc.lcBtnDnMask = lc.lcBtnUpMask = ~0;
+             WTInfo (WTI_DDCTXS + i, CTX_INORGX, &lc.lcInOrgX);
+             WTInfo (WTI_DDCTXS + i, CTX_INORGY, &lc.lcInOrgY);
+             WTInfo (WTI_DDCTXS + i, CTX_INORGZ, &lc.lcInOrgZ);
+             WTInfo (WTI_DDCTXS + i, CTX_INEXTX, &lc.lcInExtX);
+             WTInfo (WTI_DDCTXS + i, CTX_INEXTY, &lc.lcInExtY);
+             WTInfo (WTI_DDCTXS + i, CTX_INEXTZ, &lc.lcInExtZ);
+             lc.lcOutOrgX = axis_x.axMin;
+             lc.lcOutOrgY = axis_y.axMin;
+             lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
+             lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
+             lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
+             WTInfo (WTI_DDCTXS + i, CTX_SENSX, &lc.lcSensX);
+             WTInfo (WTI_DDCTXS + i, CTX_SENSY, &lc.lcSensY);
+             WTInfo (WTI_DDCTXS + i, CTX_SENSZ, &lc.lcSensZ);
+             WTInfo (WTI_DDCTXS + i, CTX_SYSMODE, &lc.lcSysMode);
+             lc.lcSysOrgX = lc.lcSysOrgY = 0;
+             WTInfo (WTI_DDCTXS + i, CTX_SYSEXTX, &lc.lcSysExtX);
+             WTInfo (WTI_DDCTXS + i, CTX_SYSEXTY, &lc.lcSysExtY);
+             WTInfo (WTI_DDCTXS + i, CTX_SYSSENSX, &lc.lcSysSensX);
+             WTInfo (WTI_DDCTXS + i, CTX_SYSSENSY, &lc.lcSysSensY);
+           }
+         else
+           {
+             lc = defcontext;
+             lc.lcOptions |= CXO_MESSAGES;
+             lc.lcMsgBase = WT_DEFBASE;
+             lc.lcPktRate = 20; /* Slow down the packets a bit */
+             lc.lcPktData = PACKETDATA;
+             lc.lcPktMode = PACKETMODE;
+             lc.lcMoveMask = PACKETDATA;
+             lc.lcBtnUpMask = lc.lcBtnDnMask = ~0;
+#if 0
+             lc.lcOutExtY = -lc.lcOutExtY; /* Y grows downward */
+#else
+             lc.lcOutOrgX = axis_x.axMin;
+             lc.lcOutOrgY = axis_y.axMin;
+             lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
+             lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
+             lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
+#endif
+           }
+#if 0
+         g_print("context for device %d:\n", i); print_lc(&lc);
+#endif
+         hctx = g_new (HCTX, 1);
+          if ((*hctx = WTOpen (window_private->xwindow, &lc, TRUE)) == NULL)
+           {
+             g_warning ("gdk_input_init: WTOpen failed");
+             return;
+           }
+         GDK_NOTE (MISC, g_print ("gdk_input_init: opened Wintab device %d %#x\n",
+                                  i, *hctx));
+
+         wintab_contexts = g_list_append (wintab_contexts, hctx);
+#if 0
+         WTEnable (*hctx, TRUE);
+#endif
+         WTOverlap (*hctx, TRUE);
+
+#if 0
+         g_print("context for device %d after WTOpen:\n", i); print_lc(&lc);
+#endif
+         for (j = firstcsr; j < firstcsr + ncsrtypes; j++)
+           {
+             gdkdev = g_new (GdkDevicePrivate, 1);
+             WTInfo (WTI_CURSORS + j, CSR_NAME, csrname);
+             gdkdev->info.name = g_strconcat (devname, " ", csrname, NULL);
+             gdkdev->info.deviceid = deviceid_counter++;
+             gdkdev->info.source = GDK_SOURCE_PEN;
+             gdkdev->info.mode = GDK_MODE_SCREEN;
+#if USE_SYSCONTEXT
+             gdkdev->info.has_cursor = TRUE;
+#else
+             gdkdev->info.has_cursor = FALSE;
+#endif
+             gdkdev->hctx = *hctx;
+             gdkdev->cursor = j;
+             WTInfo (WTI_CURSORS + j, CSR_PKTDATA, &gdkdev->pktdata);
+             gdkdev->info.num_axes = 0;
+             if (gdkdev->pktdata & PK_X)
+               gdkdev->info.num_axes++;
+             if (gdkdev->pktdata & PK_Y)
+               gdkdev->info.num_axes++;
+             if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
+               gdkdev->info.num_axes++;
+             if (gdkdev->pktdata & PK_ORIENTATION)
+               gdkdev->info.num_axes += 2; /* x and y tilt */
+             WTInfo (WTI_CURSORS + j, CSR_NPBTNMARKS, &gdkdev->npbtnmarks);
+             gdkdev->axes = g_new (GdkAxisInfo, gdkdev->info.num_axes);
+             gdkdev->info.axes = g_new (GdkAxisUse, gdkdev->info.num_axes);
+             gdkdev->last_axis_data = g_new (gint, gdkdev->info.num_axes);
+             
+             for (k = 0; k < GDK_AXIS_LAST; k++)
+               gdkdev->axis_for_use[k] = -1;
+
+             k = 0;
+             if (gdkdev->pktdata & PK_X)
+               {
+                 gdkdev->axes[k].xresolution =
+                   gdkdev->axes[k].resolution = axis_x.axResolution / 65535.;
+                 gdkdev->axes[k].xmin_value =
+                   gdkdev->axes[k].min_value = axis_x.axMin;
+                 gdkdev->axes[k].xmax_value =
+                   gdkdev->axes[k].max_value = axis_x.axMax;
+                 gdkdev->info.axes[k] = GDK_AXIS_X;
+                 gdkdev->axis_for_use[GDK_AXIS_X] = k;
+                 k++;
+               }
+             if (gdkdev->pktdata & PK_Y)
+               {
+                 gdkdev->axes[k].xresolution =
+                   gdkdev->axes[k].resolution = axis_y.axResolution / 65535.;
+                 gdkdev->axes[k].xmin_value =
+                   gdkdev->axes[k].min_value = axis_y.axMin;
+                 gdkdev->axes[k].xmax_value =
+                   gdkdev->axes[k].max_value = axis_y.axMax;
+                 gdkdev->info.axes[k] = GDK_AXIS_Y;
+                 gdkdev->axis_for_use[GDK_AXIS_Y] = k;
+                 k++;
+               }
+             if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
+               {
+                 gdkdev->axes[k].xresolution =
+                   gdkdev->axes[k].resolution = axis_npressure.axResolution / 65535.;
+                 gdkdev->axes[k].xmin_value =
+                   gdkdev->axes[k].min_value = axis_npressure.axMin;
+                 gdkdev->axes[k].xmax_value =
+                   gdkdev->axes[k].max_value = axis_npressure.axMax;
+                 gdkdev->info.axes[k] = GDK_AXIS_PRESSURE;
+                 gdkdev->axis_for_use[GDK_AXIS_PRESSURE] = k;
+                 k++;
+               }
+             if (gdkdev->pktdata & PK_ORIENTATION)
+               {
+                 GdkAxisUse axis;
+
+                 gdkdev->orientation_axes[0] = axis_orientation[0];
+                 gdkdev->orientation_axes[1] = axis_orientation[1];
+                 for (axis = GDK_AXIS_XTILT; axis <= GDK_AXIS_YTILT; axis++)
+                   {
+                     gdkdev->axes[k].xresolution =
+                       gdkdev->axes[k].resolution = 1000;
+                     gdkdev->axes[k].xmin_value =
+                       gdkdev->axes[k].min_value = -1000;
+                     gdkdev->axes[k].xmax_value =
+                       gdkdev->axes[k].max_value = 1000;
+                     gdkdev->info.axes[k] = axis;
+                     gdkdev->axis_for_use[axis] = k;
+                     k++;
+                   }
+               }
+             gdkdev->info.num_keys = 0;
+             gdkdev->info.keys = NULL;
+             GDK_NOTE (EVENTS,
+                       g_print ("gdk_input_init: device: %d axes: %d\n",
+                                gdkdev->info.deviceid,
+                                gdkdev->info.num_axes));
+             gdk_input_devices = g_list_append (gdk_input_devices,
+                                                gdkdev);
+           }
+       }
+      gdk_input_vtable.set_mode           = gdk_input_win32_set_mode;
+      gdk_input_vtable.set_axes           = NULL;
+      gdk_input_vtable.set_key            = NULL;
+      gdk_input_vtable.motion_events      = NULL;
+      gdk_input_vtable.get_pointer       = gdk_input_win32_get_pointer;
+      gdk_input_vtable.grab_pointer      = gdk_input_win32_grab_pointer;
+      gdk_input_vtable.ungrab_pointer     = gdk_input_win32_ungrab_pointer;
+      gdk_input_vtable.configure_event    = gdk_input_win32_configure_event;
+      gdk_input_vtable.enter_event        = gdk_input_win32_enter_event;
+      gdk_input_vtable.other_event        = gdk_input_win32_other_event;
+      gdk_input_vtable.enable_window      = gdk_input_win32_enable_window;
+      gdk_input_vtable.disable_window     = gdk_input_win32_disable_window;
+
+      gdk_input_root_width = gdk_screen_width ();
+      gdk_input_root_height = gdk_screen_height ();
+      gdk_input_ignore_core = FALSE;
+    }
+  else
+    {
+      gdk_input_vtable.set_mode           = NULL;
+      gdk_input_vtable.set_axes           = NULL;
+      gdk_input_vtable.set_key            = NULL;
+      gdk_input_vtable.motion_events      = NULL;
+      gdk_input_vtable.get_pointer       = gdk_input_none_get_pointer;
+      gdk_input_vtable.grab_pointer      = NULL;
+      gdk_input_vtable.ungrab_pointer     = NULL;
+      gdk_input_vtable.configure_event    = NULL;
+      gdk_input_vtable.enter_event        = NULL;
+      gdk_input_vtable.other_event        = NULL;
+      gdk_input_vtable.enable_window      = NULL;
+      gdk_input_vtable.disable_window     = NULL;
+      gdk_input_ignore_core = FALSE;
+    }
+  
+  gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info);
+}
+
+static void
+gdk_input_get_root_relative_geometry (HWND w,
+                                     int  *x_ret,
+                                     int  *y_ret)
+{
+  RECT rect;
+
+  GetWindowRect (w, &rect);
+
+  if (x_ret)
+    *x_ret = rect.left;
+  if (y_ret)
+    *y_ret = rect.top;
+}
+
+static void
+gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
+                                GdkInputWindow   *input_window,
+                                gint             *axis_data,
+                                gdouble          *x,
+                                gdouble          *y,
+                                gdouble          *pressure,
+                                gdouble          *xtilt,
+                                gdouble          *ytilt)
+{
+  GdkWindowPrivate *window_private;
+  gint x_axis, y_axis, pressure_axis, xtilt_axis, ytilt_axis;
+  gdouble device_width, device_height;
+  gdouble x_offset, y_offset, x_scale, y_scale;
+
+  window_private = (GdkWindowPrivate *) input_window->window;
+
+  x_axis = gdkdev->axis_for_use[GDK_AXIS_X];
+  y_axis = gdkdev->axis_for_use[GDK_AXIS_Y];
+  pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE];
+  xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT];
+  ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT];
+
+  device_width = gdkdev->axes[x_axis].max_value - 
+                  gdkdev->axes[x_axis].min_value;
+  device_height = gdkdev->axes[y_axis].max_value - 
+                    gdkdev->axes[y_axis].min_value;
+
+  if (gdkdev->info.mode == GDK_MODE_SCREEN) 
+    {
+      x_scale = gdk_input_root_width / device_width;
+      y_scale = gdk_input_root_height / device_height;
+
+      x_offset = -input_window->root_x;
+      y_offset = -input_window->root_y;
+    }
+  else                         /* GDK_MODE_WINDOW */
+    {
+      double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) /
+       (device_width*gdkdev->axes[x_axis].resolution);
+
+      if (device_aspect * window_private->width >= window_private->height)
+       {
+         /* device taller than window */
+         x_scale = window_private->width / device_width;
+         y_scale = (x_scale * gdkdev->axes[x_axis].resolution)
+           / gdkdev->axes[y_axis].resolution;
+
+         x_offset = 0;
+         y_offset = -(device_height * y_scale - 
+                              window_private->height)/2;
+       }
+      else
+       {
+         /* window taller than device */
+         y_scale = window_private->height / device_height;
+         x_scale = (y_scale * gdkdev->axes[y_axis].resolution)
+           / gdkdev->axes[x_axis].resolution;
+
+         y_offset = 0;
+         x_offset = -(device_width * x_scale - window_private->width)/2;
+       }
+    }
+  
+  if (x)
+    *x = x_offset + x_scale*axis_data[x_axis];
+  if (y)
+    *y = y_offset + y_scale*axis_data[y_axis];
+
+  if (pressure)
+    {
+      if (pressure_axis != -1)
+       *pressure = ((double)axis_data[pressure_axis] 
+                    - gdkdev->axes[pressure_axis].min_value) 
+         / (gdkdev->axes[pressure_axis].max_value 
+            - gdkdev->axes[pressure_axis].min_value);
+      else
+       *pressure = 0.5;
+    }
+
+  if (xtilt)
+    {
+      if (xtilt_axis != -1)
+       {
+         *xtilt = 2. * (double)(axis_data[xtilt_axis] - 
+                                (gdkdev->axes[xtilt_axis].min_value +
+                                 gdkdev->axes[xtilt_axis].max_value)/2) /
+           (gdkdev->axes[xtilt_axis].max_value -
+            gdkdev->axes[xtilt_axis].min_value);
+       }
+      else
+       *xtilt = 0;
+    }
+  
+  if (ytilt)
+    {
+      if (ytilt_axis != -1)
+       {
+         *ytilt = 2. * (double)(axis_data[ytilt_axis] - 
+                                (gdkdev->axes[ytilt_axis].min_value +
+                                 gdkdev->axes[ytilt_axis].max_value)/2) /
+           (gdkdev->axes[ytilt_axis].max_value -
+            gdkdev->axes[ytilt_axis].min_value);
+       }
+      else
+       *ytilt = 0;
+    }
+}
+
+gint
+gdk_input_set_mode (guint32      deviceid,
+                   GdkInputMode mode)
+{
+  if (deviceid == GDK_CORE_POINTER)
+    return FALSE;
+
+  if (gdk_input_vtable.set_mode)
+    return gdk_input_vtable.set_mode (deviceid, mode);
+  else
+    return FALSE;
+}
+
+void
+gdk_input_set_axes (guint32     deviceid,
+                   GdkAxisUse *axes)
+{
+  int i;
+  GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid);
+  g_return_if_fail (gdkdev != NULL);
+
+  if (deviceid == GDK_CORE_POINTER)
+    return;
+
+  for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++)
+    {
+      gdkdev->axis_for_use[i] = -1;
+    }
+
+  for (i = 0; i < gdkdev->info.num_axes; i++)
+    {
+      gdkdev->info.axes[i] = axes[i];
+      gdkdev->axis_for_use[axes[i]] = i;
+    }
+}
+
+static void 
+gdk_input_win32_get_pointer (GdkWindow       *window,
+                            guint32          deviceid,
+                            gdouble         *x,
+                            gdouble         *y,
+                            gdouble         *pressure,
+                            gdouble         *xtilt,
+                            gdouble         *ytilt,
+                            GdkModifierType *mask)
+{
+  GdkDevicePrivate *gdkdev;
+  GdkInputWindow *input_window;
+  gint x_int, y_int;
+  gint i;
+
+  if (deviceid == GDK_CORE_POINTER)
+    {
+      gdk_window_get_pointer (window, &x_int, &y_int, mask);
+      if (x)
+       *x = x_int;
+      if (y)
+       *y = y_int;
+      if (pressure)
+       *pressure = 0.5;
+      if (xtilt)
+       *xtilt = 0;
+      if (ytilt)
+       *ytilt = 0;
+    }
+  else
+    {
+      if (mask)
+       gdk_window_get_pointer (window, NULL, NULL, mask);
+      
+      gdkdev = gdk_input_find_device (deviceid);
+      g_return_if_fail (gdkdev != NULL);
+
+      input_window = gdk_input_window_find (window);
+      g_return_if_fail (input_window != NULL);
+
+      gdk_input_translate_coordinates (gdkdev, input_window,
+                                      gdkdev->last_axis_data,
+                                      x, y, pressure,
+                                      xtilt, ytilt);
+      if (mask)
+       {
+         *mask &= 0xFF;
+         *mask |= ((gdkdev->last_buttons & 0x1F) << 8);
+       }
+    }
+}
+
+static void
+gdk_input_none_get_pointer (GdkWindow       *window,
+                           guint32          deviceid,
+                           gdouble         *x,
+                           gdouble         *y,
+                           gdouble         *pressure,
+                           gdouble         *xtilt,
+                           gdouble         *ytilt,
+                           GdkModifierType *mask)
+{
+  gint x_int, y_int;
+
+  gdk_window_get_pointer (window, &x_int, &y_int, mask);
+
+  if (x)
+    *x = x_int;
+  if (y)
+    *y = y_int;
+  if (pressure)
+    *pressure = 0.5;
+  if (xtilt)
+    *xtilt = 0;
+  if (ytilt)
+    *ytilt = 0;
+}
+
+static gint
+gdk_input_win32_set_mode (guint32      deviceid,
+                         GdkInputMode mode)
+{
+  GList *tmp_list;
+  GdkDevicePrivate *gdkdev;
+  GdkInputMode old_mode;
+  GdkInputWindow *input_window;
+
+  if (deviceid == GDK_CORE_POINTER)
+    return FALSE;
+
+  gdkdev = gdk_input_find_device (deviceid);
+  g_return_val_if_fail (gdkdev != NULL, FALSE);
+  old_mode = gdkdev->info.mode;
+
+  if (old_mode == mode)
+    return TRUE;
+
+  gdkdev->info.mode = mode;
+
+  if (mode == GDK_MODE_WINDOW)
+    {
+      gdkdev->info.has_cursor = FALSE;
+      for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
+       {
+         input_window = (GdkInputWindow *)tmp_list->data;
+         if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
+           gdk_input_win32_enable_window (input_window->window, gdkdev);
+         else
+           if (old_mode != GDK_MODE_DISABLED)
+             gdk_input_win32_disable_window (input_window->window, gdkdev);
+       }
+    }
+  else if (mode == GDK_MODE_SCREEN)
+    {
+      gdkdev->info.has_cursor = TRUE;
+      for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
+       gdk_input_win32_enable_window (((GdkInputWindow *)tmp_list->data)->window,
+                                      gdkdev);
+    }
+  else  /* mode == GDK_MODE_DISABLED */
+    {
+      for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
+       {
+         input_window = (GdkInputWindow *)tmp_list->data;
+         if (old_mode != GDK_MODE_WINDOW ||
+             input_window->mode != GDK_EXTENSION_EVENTS_CURSOR)
+           gdk_input_win32_disable_window (input_window->window, gdkdev);
+       }
+    }
+
+  return TRUE;
+}
+
+static void
+gdk_input_win32_configure_event (GdkEventConfigure *event,
+                                GdkWindow         *window)
+{
+  GdkInputWindow *input_window;
+  gint root_x, root_y;
+
+  input_window = gdk_input_window_find (window);
+  g_return_if_fail (window != NULL);
+
+  gdk_input_get_root_relative_geometry (GDK_WINDOW_XWINDOW (window),
+                                       &root_x, &root_y);
+
+  input_window->root_x = root_x;
+  input_window->root_y = root_y;
+}
+
+static void 
+gdk_input_win32_enter_event (GdkEventCrossing *event, 
+                            GdkWindow        *window)
+{
+  GdkInputWindow *input_window;
+  gint root_x, root_y;
+
+  input_window = gdk_input_window_find (window);
+  g_return_if_fail (window != NULL);
+
+  gdk_input_get_root_relative_geometry (GDK_WINDOW_XWINDOW (window),
+                                       &root_x, &root_y);
+
+  input_window->root_x = root_x;
+  input_window->root_y = root_y;
+}
+
+static void
+decode_tilt (gint   *axis_data,
+            AXIS   *axes,
+            PACKET *packet)
+{
+  /* As I don't have a tilt-sensing tablet,
+   * I cannot test this code.
+   */
+  
+  double az, el;
+
+  az = TWOPI * packet->pkOrientation.orAzimuth /
+    (axes[0].axResolution / 65536.);
+  el = TWOPI * packet->pkOrientation.orAltitude /
+    (axes[1].axResolution / 65536.);
+  
+  /* X tilt */
+  axis_data[0] = cos (az) * cos (el) * 1000;
+  /* Y tilt */
+  axis_data[1] = sin (az) * cos (el) * 1000;
+}
+
+static gint 
+gdk_input_win32_other_event (GdkEvent  *event,
+                            MSG       *xevent)
+{
+  GdkWindow *current_window;
+  GdkInputWindow *input_window;
+  GdkWindow *window;
+  GdkWindowPrivate *window_private;
+  GdkDevicePrivate *gdkdev;
+  GdkEventMask masktest;
+  POINT pt;
+  PACKET packet;
+  gint return_val;
+  gint k;
+  gint x, y;
+
+  if (event->any.window != wintab_window)
+    g_warning ("gdk_input_win32_other_event: not wintab_window?");
+
+#if USE_SYSCONTEXT
+  window = gdk_window_at_pointer (&x, &y);
+  if (window == NULL)
+    window = (GdkWindow *) &gdk_root_parent;
+
+  gdk_window_ref (window);
+
+  window_private = (GdkWindowPrivate *) window;
+
+  GDK_NOTE (EVENTS, g_print ("gdk_input_win32_other_event: window=%#x (%d,%d)\n", window_private->xwindow, x, y));
+  
+#else
+  /* ??? This code is pretty bogus */
+  current_window = gdk_window_lookup (GetActiveWindow ());
+  if (current_window == NULL)
+    return FALSE;
+  
+  input_window = gdk_input_window_find_within (current_window);
+  if (input_window == NULL)
+    return FALSE;
+#endif
+
+  if (xevent->message == WT_PACKET)
+    {
+      if (!WTPacket ((HCTX) xevent->lParam, xevent->wParam, &packet))
+       return FALSE;
+    }
+
+  switch (xevent->message)
+    {
+    case WT_PACKET:
+      if (window_private == &gdk_root_parent)
+       {
+         GDK_NOTE (EVENTS, g_print ("...is root\n"));
+         return FALSE;
+       }
+
+      if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) xevent->lParam,
+                                                packet.pkCursor)) == NULL)
+       return FALSE;
+
+      if (gdkdev->info.mode == GDK_MODE_DISABLED)
+       return FALSE;
+      
+      k = 0;
+      if (gdkdev->pktdata & PK_X)
+       gdkdev->last_axis_data[k++] = packet.pkX;
+      if (gdkdev->pktdata & PK_Y)
+       gdkdev->last_axis_data[k++] = packet.pkY;
+      if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
+       gdkdev->last_axis_data[k++] = packet.pkNormalPressure;
+      if (gdkdev->pktdata & PK_ORIENTATION)
+       {
+         decode_tilt (gdkdev->last_axis_data + k,
+                      gdkdev->orientation_axes, &packet);
+         k += 2;
+       }
+
+      g_assert (k == gdkdev->info.num_axes);
+
+      if (HIWORD (packet.pkButtons) != TBN_NONE)
+       {
+         /* Gdk buttons are numbered 1.. */
+         event->button.button = 1 + LOWORD (packet.pkButtons);
+
+         if (HIWORD (packet.pkButtons) == TBN_UP)
+           {
+             event->any.type = GDK_BUTTON_RELEASE;
+             masktest = GDK_BUTTON_RELEASE_MASK;
+             gdkdev->button_state &= ~(1 << LOWORD (packet.pkButtons));
+           }
+         else
+           {
+             event->any.type = GDK_BUTTON_PRESS;
+             masktest = GDK_BUTTON_PRESS_MASK;
+             gdkdev->button_state |= 1 << LOWORD (packet.pkButtons);
+           }
+       }
+      else
+       {
+         event->any.type = GDK_MOTION_NOTIFY;
+         masktest = GDK_POINTER_MOTION_MASK;
+         if (gdkdev->button_state & (1 << 0))
+           masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK;
+         if (gdkdev->button_state & (1 << 1))
+           masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK;
+         if (gdkdev->button_state & (1 << 2))
+           masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK;
+       }
+
+      /* Now we can check if the window wants the event, and
+       * propagate if necessary.
+       */
+    dijkstra:
+      if (!window_private->extension_events_selected
+         || !(window_private->extension_events & masktest))
+       {
+         GDK_NOTE (EVENTS, g_print ("...not selected\n"));
+
+         if (window_private->parent == (GdkWindow *) &gdk_root_parent)
+           return FALSE;
+         
+         pt.x = x;
+         pt.y = y;
+         ClientToScreen (window_private->xwindow, &pt);
+         gdk_window_unref (window);
+         window = window_private->parent;
+         gdk_window_ref (window);
+         window_private = (GdkWindowPrivate *) window;
+         ScreenToClient (window_private->xwindow, &pt);
+         x = pt.x;
+         y = pt.y;
+         GDK_NOTE (EVENTS, g_print ("...propagating to %#x, (%d,%d)\n", window_private->xwindow, x, y));
+         goto dijkstra;
+       }
+
+      input_window = gdk_input_window_find (window);
+
+      g_assert (input_window != NULL);
+
+      if (gdkdev->info.mode == GDK_MODE_WINDOW
+         && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)
+       return FALSE;
+
+      event->any.window = window;
+
+      if (event->any.type == GDK_BUTTON_PRESS
+         || event->any.type == GDK_BUTTON_RELEASE)
+       {
+         event->button.time = xevent->time;
+         event->button.source = gdkdev->info.source;
+         last_moved_cursor_id = 
+           event->button.deviceid = gdkdev->info.deviceid;
+         
+#if 0
+#if USE_SYSCONTEXT
+         /* Buttons 1 to 3 will come in as WM_[LMR]BUTTON{DOWN,UP} */
+         if (event->button.button <= 3)
+           return FALSE;
+#endif
+#endif
+         gdk_input_translate_coordinates (gdkdev, input_window,
+                                          gdkdev->last_axis_data,
+                                          &event->button.x, &event->button.y,
+                                          &event->button.pressure,
+                                          &event->button.xtilt, 
+                                          &event->button.ytilt);
+
+         event->button.state = ((gdkdev->button_state << 8)
+                                & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+                                   | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+                                   | GDK_BUTTON5_MASK));
+         GDK_NOTE (EVENTS, g_print ("WINTAB button %s: %d %d %g,%g %g\n",
+                                    (event->button.type == GDK_BUTTON_PRESS ?
+                                     "press" : "release"),
+                                    event->button.deviceid,
+                                    event->button.button,
+                                    event->button.x, event->button.y,
+                                    event->button.pressure));
+       }
+      else
+       {
+         event->motion.time = xevent->time;
+         last_moved_cursor_id =
+           event->motion.deviceid = gdkdev->info.deviceid;
+         event->motion.is_hint = FALSE;
+         event->motion.source = gdkdev->info.source;
+
+         gdk_input_translate_coordinates (gdkdev, input_window,
+                                          gdkdev->last_axis_data,
+                                          &event->motion.x, &event->motion.y,
+                                          &event->motion.pressure,
+                                          &event->motion.xtilt, 
+                                          &event->motion.ytilt);
+
+         event->motion.state = ((gdkdev->button_state << 8)
+                                & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+                                   | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+                                   | GDK_BUTTON5_MASK));
+
+         GDK_NOTE (EVENTS, g_print ("WINTAB motion: %d %g,%g %g\n",
+                                    event->motion.deviceid,
+                                    event->motion.x, event->motion.y,
+                                    event->motion.pressure));
+
+         /* Check for missing release or press events for the normal
+          * pressure button. At least on my ArtPadII I sometimes miss a
+          * release event?
+          */
+         if ((gdkdev->pktdata & PK_NORMAL_PRESSURE
+              && (event->motion.state & GDK_BUTTON1_MASK)
+              && packet.pkNormalPressure <= MAX (0, gdkdev->npbtnmarks[0] - 2))
+             || (gdkdev->pktdata & PK_NORMAL_PRESSURE
+                 && !(event->motion.state & GDK_BUTTON1_MASK)
+                 && packet.pkNormalPressure > gdkdev->npbtnmarks[1] + 2))
+           {
+             GdkEvent *event2 = gdk_event_copy (event);
+             if (event->motion.state & GDK_BUTTON1_MASK)
+               {
+                 event2->button.type = GDK_BUTTON_RELEASE;
+                 gdkdev->button_state &= ~1;
+               }
+             else
+               {
+                 event2->button.type = GDK_BUTTON_PRESS;
+                 gdkdev->button_state |= 1;
+               }
+             event2->button.state = ((gdkdev->button_state << 8)
+                                     & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
+                                        | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
+                                        | GDK_BUTTON5_MASK));
+             event2->button.button = 1;
+             GDK_NOTE (EVENTS, g_print ("WINTAB synthesized button %s: %d %d %g,%g %g\n",
+                                        (event2->button.type == GDK_BUTTON_PRESS ?
+                                         "press" : "release"),
+                                        event2->button.deviceid,
+                                        event2->button.button,
+                                        event2->button.x, event2->button.y,
+                                        event2->button.pressure));
+             gdk_event_queue_append (event2);
+           }
+       }
+      return TRUE;
+
+    case WT_PROXIMITY:
+      if (LOWORD (xevent->lParam) == 0)
+       {
+         event->proximity.type = GDK_PROXIMITY_OUT;
+         gdk_input_ignore_core = FALSE;
+       }
+      else
+       {
+         event->proximity.type = GDK_PROXIMITY_IN;
+         gdk_input_ignore_core = TRUE;
+       }
+      event->proximity.time = xevent->time;
+      event->proximity.source = GDK_SOURCE_PEN;
+      event->proximity.deviceid = last_moved_cursor_id;
+
+      GDK_NOTE (EVENTS, g_print ("WINTAB proximity %s: %d\n",
+                                (event->proximity.type == GDK_PROXIMITY_IN ?
+                                 "in" : "out"),
+                                event->proximity.deviceid));
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gint
+gdk_input_win32_enable_window (GdkWindow        *window,
+                              GdkDevicePrivate *gdkdev)
+{
+  GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
+
+  window_private->extension_events_selected = TRUE;
+  return TRUE;
+}
+
+static gint
+gdk_input_win32_disable_window (GdkWindow        *window,
+                               GdkDevicePrivate *gdkdev)
+{
+  GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
+
+  window_private->extension_events_selected = FALSE;
+  return TRUE;
+}
+
+static gint
+gdk_input_win32_grab_pointer (GdkWindow    *window,
+                             gint          owner_events,
+                             GdkEventMask  event_mask,
+                             GdkWindow    *confine_to,
+                             guint32       time)
+{
+  GdkInputWindow *input_window, *new_window;
+  gboolean need_ungrab;
+  GdkDevicePrivate *gdkdev;
+  GList *tmp_list;
+  gint result;
+
+  tmp_list = gdk_input_windows;
+  new_window = NULL;
+  need_ungrab = FALSE;
+
+  while (tmp_list)
+    {
+      input_window = (GdkInputWindow *)tmp_list->data;
+
+      if (input_window->window == window)
+       new_window = input_window;
+      else if (input_window->grabbed)
+       {
+         input_window->grabbed = FALSE;
+         need_ungrab = TRUE;
+       }
+
+      tmp_list = tmp_list->next;
+    }
+
+  if (new_window)
+    {
+      new_window->grabbed = TRUE;
+      
+      tmp_list = gdk_input_devices;
+      while (tmp_list)
+       {
+         gdkdev = (GdkDevicePrivate *)tmp_list->data;
+         if (gdkdev->info.deviceid != GDK_CORE_POINTER)
+           {
+#if 0        
+             gdk_input_find_events (window, gdkdev,
+                                    event_mask,
+                                    event_classes, &num_classes);
+             result = XGrabDevice (GDK_DISPLAY(), gdkdev->xdevice,
+                                   GDK_WINDOW_XWINDOW (window),
+                                   owner_events, num_classes, event_classes,
+                                   GrabModeAsync, GrabModeAsync, time);
+             
+             /* FIXME: if failure occurs on something other than the first
+                device, things will be badly inconsistent */
+             if (result != Success)
+               return result;
+#endif
+           }
+         tmp_list = tmp_list->next;
+       }
+    }
+  else
+    { 
+      tmp_list = gdk_input_devices;
+      while (tmp_list)
+       {
+         gdkdev = (GdkDevicePrivate *)tmp_list->data;
+         if (gdkdev->info.deviceid != GDK_CORE_POINTER && 
+             ((gdkdev->button_state != 0) || need_ungrab))
+           {
+#if 0
+             XUngrabDevice (gdk_display, gdkdev->xdevice, time);
+#endif
+             gdkdev->button_state = 0;
+           }
+         
+         tmp_list = tmp_list->next;
+       }
+    }
+
+  return Success;
+      
+}
+
+static void 
+gdk_input_win32_ungrab_pointer (guint32 time)
+{
+  GdkInputWindow *input_window;
+  GdkDevicePrivate *gdkdev;
+  GList *tmp_list;
+
+  tmp_list = gdk_input_windows;
+  while (tmp_list)
+    {
+      input_window = (GdkInputWindow *)tmp_list->data;
+      if (input_window->grabbed)
+       break;
+      tmp_list = tmp_list->next;
+    }
+
+  if (tmp_list)                        /* we found a grabbed window */
+    {
+      input_window->grabbed = FALSE;
+
+      tmp_list = gdk_input_devices;
+      while (tmp_list)
+       {
+         gdkdev = (GdkDevicePrivate *)tmp_list->data;
+#if 0
+         if (gdkdev->info.deviceid != GDK_CORE_POINTER && gdkdev->xdevice)
+           XUngrabDevice (gdk_display, gdkdev->xdevice, time);
+#endif
+         tmp_list = tmp_list->next;
+       }
+    }
+}
+
+GList *
+gdk_input_list_devices (void)
+{
+  return gdk_input_devices;
+}
+
+void
+gdk_input_set_source (guint32        deviceid,
+                     GdkInputSource source)
+{
+  GdkDevicePrivate *gdkdev = gdk_input_find_device (deviceid);
+  g_return_if_fail (gdkdev != NULL);
+
+  gdkdev->info.source = source;
+}
+
+void gdk_input_set_key (guint32 deviceid,
+                       guint   index,
+                       guint   keyval,
+                       GdkModifierType modifiers)
+{
+  if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_key)
+    gdk_input_vtable.set_key (deviceid, index, keyval, modifiers);
+}
+
+GdkTimeCoord *
+gdk_input_motion_events (GdkWindow *window,
+                        guint32    deviceid,
+                        guint32    start,
+                        guint32    stop,
+                        gint      *nevents_return)
+{
+  GdkWindowPrivate *window_private;
+  GdkTimeCoord *coords;
+  int i;
+
+  g_return_val_if_fail (window != NULL, NULL);
+  window_private = (GdkWindowPrivate *) window;
+  if (window_private->destroyed)
+    return NULL;
+
+  *nevents_return = 0;
+  return NULL;         /* ??? */
+}
+
+static GdkInputWindow *
+gdk_input_window_find (GdkWindow *window)
+{
+  GList *tmp_list;
+
+  for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next)
+    if (((GdkInputWindow *)(tmp_list->data))->window == window)
+      return (GdkInputWindow *)(tmp_list->data);
+
+  return NULL;      /* Not found */
+}
+
+static GdkInputWindow *
+gdk_input_window_find_within (GdkWindow *window)
+{
+  GList *tmp_list;
+  GdkWindowPrivate *window_private;
+  GdkWindowPrivate *tmp_private;
+  GdkInputWindow *candidate = NULL;
+
+  window_private = (GdkWindowPrivate *) window;
+
+  for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next)
+    {
+      (GdkWindowPrivate *) tmp_private =
+       (GdkWindowPrivate *) (((GdkInputWindow *)(tmp_list->data))->window);
+      if (tmp_private == window_private
+         || IsChild (window_private->xwindow, tmp_private->xwindow))
+       {
+         if (candidate)
+           return NULL;                /* Multiple hits */
+         candidate = (GdkInputWindow *)(tmp_list->data);
+       }
+    }
+
+  return candidate;
+}
+
+/* FIXME: this routine currently needs to be called between creation
+   and the corresponding configure event (because it doesn't get the
+   root_relative_geometry).  This should work with
+   gtk_window_set_extension_events, but will likely fail in other
+   cases */
+
+void
+gdk_input_set_extension_events (GdkWindow       *window,
+                               gint             mask,
+                               GdkExtensionMode mode)
+{
+  GdkWindowPrivate *window_private;
+  GList *tmp_list;
+  GdkInputWindow *iw;
+
+  g_return_if_fail (window != NULL);
+  window_private = (GdkWindowPrivate *) window;
+  if (window_private->destroyed)
+    return;
+
+  if (mode == GDK_EXTENSION_EVENTS_NONE)
+    mask = 0;
+
+  if (mask != 0)
+    {
+      iw = g_new (GdkInputWindow,1);
+
+      iw->window = window;
+      iw->mode = mode;
+
+      iw->grabbed = FALSE;
+
+      gdk_input_windows = g_list_append (gdk_input_windows, iw);
+      window_private->extension_events = mask;
+
+      /* Add enter window events to the event mask */
+      gdk_window_set_events (window,
+                            gdk_window_get_events (window) | 
+                            GDK_ENTER_NOTIFY_MASK);
+    }
+  else
+    {
+      iw = gdk_input_window_find (window);
+      if (iw)
+       {
+         gdk_input_windows = g_list_remove (gdk_input_windows, iw);
+         g_free (iw);
+       }
+
+      window_private->extension_events = 0;
+    }
+
+  for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
+    {
+      GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data);
+
+      if (gdkdev->info.deviceid != GDK_CORE_POINTER)
+       {
+         if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED
+             && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL))
+           gdk_input_win32_enable_window (window, gdkdev);
+         else
+           gdk_input_win32_disable_window (window, gdkdev);
+       }
+    }
+}
+
+void
+gdk_input_window_destroy (GdkWindow *window)
+{
+  GdkInputWindow *input_window;
+
+  input_window = gdk_input_window_find (window);
+  g_return_if_fail (input_window != NULL);
+
+  gdk_input_windows = g_list_remove (gdk_input_windows,input_window);
+  g_free (input_window);
+}
+
+void
+gdk_input_exit (void)
+{
+  GList *tmp_list;
+  GdkDevicePrivate *gdkdev;
+
+  for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next)
+    {
+      gdkdev = (GdkDevicePrivate *)(tmp_list->data);
+      if (gdkdev->info.deviceid != GDK_CORE_POINTER)
+       {
+         gdk_input_win32_set_mode (gdkdev->info.deviceid, GDK_MODE_DISABLED);
+         g_free (gdkdev->info.name);
+         g_free (gdkdev->last_axis_data);
+         g_free (gdkdev->info.axes);
+         g_free (gdkdev->info.keys);
+         g_free (gdkdev->axes);
+         g_free (gdkdev);
+       }
+    }
+
+  g_list_free (gdk_input_devices);
+
+  for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next)
+    {
+      g_free (tmp_list->data);
+    }
+  g_list_free (gdk_input_windows);
+
+#if 1
+  for (tmp_list = wintab_contexts; tmp_list; tmp_list = tmp_list->next)
+    {
+      HCTX *hctx = (HCTX *) tmp_list->data;
+      BOOL result;
+
+      /* For some reason WTEnable and/or WTClose tend to crash here.
+       * Protect with __try/__except to avoid a message box.
+       */
+      __try {
+#if 0
+        WTEnable (*hctx, FALSE);
+#endif
+       result = WTClose (*hctx);
+      }
+      __except (/* GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? */
+                EXCEPTION_EXECUTE_HANDLER /*: 
+                EXCEPTION_CONTINUE_SEARCH */) {
+       result = FALSE;
+      }
+      if (!result)
+       g_warning ("gdk_input_exit: Closing Wintab context %#x failed", *hctx);
+      g_free (hctx);
+    }
+#endif
+  g_list_free (wintab_contexts);
+}
+
+static GdkDevicePrivate *
+gdk_input_find_device (guint32 id)
+{
+  GList *tmp_list = gdk_input_devices;
+  GdkDevicePrivate *gdkdev;
+
+  while (tmp_list)
+    {
+      gdkdev = (GdkDevicePrivate *) (tmp_list->data);
+      if (gdkdev->info.deviceid == id)
+       return gdkdev;
+      tmp_list = tmp_list->next;
+    }
+  return NULL;
+}
+
+static GdkDevicePrivate *
+gdk_input_find_dev_from_ctx (HCTX hctx,
+                            UINT cursor)
+{
+  GList *tmp_list = gdk_input_devices;
+  GdkDevicePrivate *gdkdev;
+
+  while (tmp_list)
+    {
+      gdkdev = (GdkDevicePrivate *) (tmp_list->data);
+      if (gdkdev->hctx == hctx && gdkdev->cursor == cursor)
+       return gdkdev;
+      tmp_list = tmp_list->next;
+    }
+  return NULL;
+}
+
+void
+gdk_input_window_get_pointer (GdkWindow       *window,
+                             guint32          deviceid,
+                             gdouble         *x,
+                             gdouble         *y,
+                             gdouble         *pressure,
+                             gdouble         *xtilt,
+                             gdouble         *ytilt,
+                             GdkModifierType *mask)
+{
+  if (gdk_input_vtable.get_pointer)
+    gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure,
+                                 xtilt, ytilt, mask);
+}
diff --git a/gdk/win32/gdkinput.h b/gdk/win32/gdkinput.h
new file mode 100644 (file)
index 0000000..46e6b1f
--- /dev/null
@@ -0,0 +1,156 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GDK_INPUT_H__
+#define __GDK_INPUT_H__
+
+#include <wintab.h>
+#define PACKETDATA (PK_CONTEXT | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y  | PK_NORMAL_PRESSURE | PK_ORIENTATION)
+#define PACKETMODE (PK_BUTTONS)
+#include <pktdef.h>
+
+typedef struct _GdkAxisInfo    GdkAxisInfo;
+typedef struct _GdkInputVTable GdkInputVTable;
+typedef struct _GdkDevicePrivate GdkDevicePrivate;
+typedef struct _GdkInputWindow GdkInputWindow;
+
+struct _GdkInputVTable {
+  gint (*set_mode) (guint32 deviceid, GdkInputMode mode);
+  void (*set_axes) (guint32 deviceid, GdkAxisUse *axes);
+  void (*set_key)  (guint32 deviceid,
+                   guint   index,
+                   guint   keyval,
+                   GdkModifierType modifiers);
+       
+  GdkTimeCoord* (*motion_events) (GdkWindow *window,
+                                 guint32 deviceid,
+                                 guint32 start,
+                                 guint32 stop,
+                                 gint *nevents_return);
+  void (*get_pointer)   (GdkWindow       *window,
+                        guint32          deviceid,
+                        gdouble         *x,
+                        gdouble         *y,
+                        gdouble         *pressure,
+                        gdouble         *xtilt,
+                        gdouble         *ytilt,
+                        GdkModifierType *mask);
+  gint (*grab_pointer) (GdkWindow *     window,
+                       gint            owner_events,
+                       GdkEventMask    event_mask,
+                       GdkWindow *     confine_to,
+                       guint32         time);
+  void (*ungrab_pointer) (guint32 time);
+
+  void (*configure_event) (GdkEventConfigure *event, GdkWindow *window);
+  void (*enter_event) (GdkEventCrossing *event, GdkWindow *window);
+  gint (*other_event) (GdkEvent *event, MSG *xevent);
+  gint (*enable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev);
+  gint (*disable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev);
+};
+
+/* information about a device axis */
+struct _GdkAxisInfo
+{
+  /* reported x resolution */
+  gint xresolution;
+
+  /* reported x minimum/maximum values */
+  gint xmin_value, xmax_value;
+
+  /* calibrated resolution (for aspect ration) - only relative values
+     between axes used */
+  gint resolution;
+  
+  /* calibrated minimum/maximum values */
+  gint min_value, max_value;
+};
+
+#define GDK_INPUT_NUM_EVENTC 6
+
+struct _GdkDevicePrivate {
+  GdkDeviceInfo  info;
+
+  /* information about the axes */
+  GdkAxisInfo *axes;
+
+  /* reverse lookup on axis use type */
+  gint axis_for_use[GDK_AXIS_LAST];
+  
+  /* true if we need to select a different set of events, but
+   * can't because this is the core pointer
+   */
+  gint needs_update;
+
+  /* State of buttons */
+  gint button_state;
+
+  gint *last_axis_data;
+  gint last_buttons;
+
+  /* WINTAB stuff: */
+  HCTX hctx;
+  /* Cursor number */
+  UINT cursor;
+  /* The cursor's CSR_PKTDATA */
+  WTPKT pktdata;
+  /* CSR_NPBTNMARKS */
+  UINT npbtnmarks[2];
+  /* Azimuth and altitude axis */
+  AXIS orientation_axes[2];
+};
+
+struct _GdkInputWindow
+{
+  /* gdk window */
+  GdkWindow *window;
+
+  /* Extension mode (GDK_EXTENSION_EVENTS_ALL/CURSOR) */
+  GdkExtensionMode mode;
+
+  /* position relative to root window */
+  gint16 root_x;
+  gint16 root_y;
+
+  /* rectangles relative to window of windows obscuring this one */
+  GdkRectangle *obscuring;
+  gint num_obscuring;
+
+  /* Is there a pointer grab for this window ? */
+  gint grabbed;
+};
+
+/* Global data */
+
+extern GdkInputVTable gdk_input_vtable;
+extern gint             gdk_input_ignore_core;
+extern gint            gdk_input_ignore_wintab;
+
+/* Function declarations */
+
+void gdk_input_window_destroy (GdkWindow *window);
+
+#endif /* __GDK_INPUT_H__ */
diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c
new file mode 100644 (file)
index 0000000..0586516
--- /dev/null
@@ -0,0 +1,2237 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-1999 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <io.h>
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkinput.h"
+#include "gdkx.h"
+#include "gdkkeysyms.h"
+#include "gdki18n.h"
+
+static void     gdkx_XConvertCase      (KeySym        symbol,
+                                        KeySym       *lower,
+                                        KeySym       *upper);
+#define XConvertCase gdkx_XConvertCase
+
+static void        gdk_exit_func                (void);
+
+static RETSIGTYPE   gdk_signal                  (int          signum);
+
+
+/* Private variable declarations
+ */
+static int gdk_initialized = 0;        /* 1 if the library is initialized,
+                                * 0 otherwise.
+                                */
+static guint start;            /* We use the millisecond
+                                * timestamps from GetTickCount
+                                */
+static gboolean timerp = TRUE; /* If TRUE use timeouts when waiting
+                                * for Windows messages
+                                */
+static guint32 timer_val = 20; /* Timeout in milliseconds.
+                                */
+
+#ifdef G_ENABLE_DEBUG
+static const GDebugKey gdk_debug_keys[] = {
+  {"events",       GDK_DEBUG_EVENTS},
+  {"misc",         GDK_DEBUG_MISC},
+  {"dnd",          GDK_DEBUG_DND},
+  {"color-context", GDK_DEBUG_COLOR_CONTEXT},
+  {"xim",          GDK_DEBUG_XIM},
+  {"selection",            GDK_DEBUG_SELECTION}
+};
+
+static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);
+
+#endif /* G_ENABLE_DEBUG */
+
+int __stdcall
+DllMain(HINSTANCE hinstDLL,
+       DWORD dwReason,
+       LPVOID reserved)
+{
+  gdk_DLLInstance = hinstDLL;
+
+  return TRUE;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_init
+ *
+ *   Initialize the library for use.
+ *
+ * Arguments:
+ *   "argc" is the number of arguments.
+ *   "argv" is an array of strings.
+ *
+ * Results:
+ *   "argc" and "argv" are modified to reflect any arguments
+ *   which were not handled. (Such arguments should either
+ *   be handled by the application or dismissed).
+ *
+ * Side effects:
+ *   The library is initialized.
+ *
+ *--------------------------------------------------------------
+ */
+
+gboolean
+gdk_init_check (int    *argc,
+               char ***argv)
+{
+  HRESULT hres;
+  gint i, j, k;
+  
+  if (gdk_initialized)
+    return TRUE;
+  
+  if (g_thread_supported ())
+    gdk_threads_mutex = g_mutex_new ();
+  
+  start = GetTickCount ();
+
+#ifdef G_ENABLE_DEBUG
+  {
+    gchar *debug_string = getenv("GDK_DEBUG");
+    if (debug_string != NULL)
+      gdk_debug_flags = g_parse_debug_string (debug_string,
+                                             (GDebugKey *) gdk_debug_keys,
+                                             gdk_ndebug_keys);
+  }
+#endif /* G_ENABLE_DEBUG */
+  
+  if (getenv ("GDK_IGNORE_WINTAB") != NULL)
+    gdk_input_ignore_wintab = TRUE;
+
+  if (argc && argv)
+    {
+      if (*argc > 0)
+       {
+         gchar *d;
+         
+         d = strrchr((*argv)[0], G_DIR_SEPARATOR);
+         if (d != NULL)
+           g_set_prgname (d + 1);
+         else
+           g_set_prgname ((*argv)[0]);
+       }
+      
+      for (i = 1; i < *argc;)
+       {
+#ifdef G_ENABLE_DEBUG    
+         if ((strcmp ("--gdk-debug", (*argv)[i]) == 0) ||
+             (strncmp ("--gdk-debug=", (*argv)[i], 12) == 0))
+           {
+             gchar *equal_pos = strchr ((*argv)[i], '=');
+             
+             if (equal_pos != NULL)
+               {
+                 gdk_debug_flags |= g_parse_debug_string (equal_pos+1,
+                                                          (GDebugKey *) gdk_debug_keys,
+                                                          gdk_ndebug_keys);
+               }
+             else if ((i + 1) < *argc && (*argv)[i + 1])
+               {
+                 gdk_debug_flags |= g_parse_debug_string ((*argv)[i+1],
+                                                          (GDebugKey *) gdk_debug_keys,
+                                                          gdk_ndebug_keys);
+                 (*argv)[i] = NULL;
+                 i += 1;
+               }
+             (*argv)[i] = NULL;
+           }
+         else if ((strcmp ("--gdk-no-debug", (*argv)[i]) == 0) ||
+                  (strncmp ("--gdk-no-debug=", (*argv)[i], 15) == 0))
+           {
+             gchar *equal_pos = strchr ((*argv)[i], '=');
+
+             if (equal_pos != NULL)
+               {
+                 gdk_debug_flags &= ~g_parse_debug_string (equal_pos+1,
+                                                           (GDebugKey *) gdk_debug_keys,
+                                                           gdk_ndebug_keys);
+               }
+             else if ((i + 1) < *argc && (*argv)[i + 1])
+               {
+                 gdk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1],
+                                                           (GDebugKey *) gdk_debug_keys,
+                                                           gdk_ndebug_keys);
+                 (*argv)[i] = NULL;
+                 i += 1;
+               }
+             (*argv)[i] = NULL;
+           }
+         else 
+#endif /* G_ENABLE_DEBUG */
+           if (strcmp ("--sync", (*argv)[i]) == 0)
+             {
+               (*argv)[i] = NULL;
+               GdiSetBatchLimit (1);
+             }
+           else if (strcmp ("--name", (*argv)[i]) == 0)
+             {
+               if ((i + 1) < *argc && (*argv)[i + 1])
+                 {
+                   (*argv)[i++] = NULL;
+                   g_set_prgname ((*argv)[i]);
+                   (*argv)[i] = NULL;
+                 }
+             }
+           else if (strcmp ("--gdk-no-wintab", (*argv)[i]) == 0
+                    || strcmp ("--gdk-ignore-wintab", (*argv)[i]) == 0)
+             {
+               (*argv)[i++] = NULL;
+               gdk_input_ignore_wintab = TRUE;
+             }
+         i += 1;
+       }
+      
+      for (i = 1; i < *argc; i++)
+       {
+         for (k = i; k < *argc; k++)
+           if ((*argv)[k] != NULL)
+             break;
+         
+         if (k > i)
+           {
+             k -= i;
+             for (j = i + k; j < *argc; j++)
+               (*argv)[j-k] = (*argv)[j];
+             *argc -= k;
+           }
+       }
+    }
+  else
+    {
+      g_set_prgname ("<unknown>");
+    }
+  
+  gdk_ProgInstance = GetModuleHandle (NULL);
+  gdk_DC = CreateDC ("DISPLAY", NULL, NULL, NULL);
+
+  gdk_selection_request_msg = RegisterWindowMessage ("gdk-selection-request");
+  gdk_selection_notify_msg = RegisterWindowMessage ("gdk-selection-notify");
+  gdk_selection_clear_msg = RegisterWindowMessage ("gdk-selection-clear");
+
+  gdk_selection_property = gdk_atom_intern ("GDK_SELECTION", FALSE);
+  gdk_clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE);
+  gdk_win32_dropfiles_atom = gdk_atom_intern ("DROPFILES_DND", FALSE);
+  gdk_ole2_dnd_atom = gdk_atom_intern ("OLE2_DND", FALSE);
+
+  gdk_progclass = g_basename (g_get_prgname ());
+  gdk_progclass[0] = toupper (gdk_progclass[0]);
+
+  gdk_root_window = HWND_DESKTOP;
+
+  g_atexit (gdk_exit_func);
+  
+  gdk_events_init ();
+  gdk_visual_init ();
+  gdk_window_init ();
+  gdk_image_init ();
+  gdk_input_init ();
+  gdk_selection_init ();
+  gdk_dnd_init ();
+
+  gdk_initialized = 1;
+
+  return TRUE;
+}
+
+void
+gdk_init (int *argc, char ***argv)
+{
+  if (!gdk_init_check (argc, argv))
+    {
+      g_warning ("cannot initialize GDK");
+      exit(1);
+    }
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_exit
+ *
+ *   Restores the library to an un-itialized state and exits
+ *   the program using the "exit" system call.
+ *
+ * Arguments:
+ *   "errorcode" is the error value to pass to "exit".
+ *
+ * Results:
+ *   Allocated structures are freed and the program exits
+ *   cleanly.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_exit (int errorcode)
+{
+  /* de-initialisation is done by the gdk_exit_func(),
+     no need to do this here (Alex J.) */
+  exit (errorcode);
+}
+
+void
+gdk_set_use_xshm (gint use_xshm)
+{
+  /* Always on */
+}
+
+gint
+gdk_get_use_xshm (void)
+{
+  return TRUE;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_time_get
+ *
+ *   Get the number of milliseconds since the library was
+ *   initialized.
+ *
+ * Arguments:
+ *
+ * Results:
+ *   The time since the library was initialized is returned.
+ *   This time value is accurate to milliseconds even though
+ *   a more accurate time down to the microsecond could be
+ *   returned.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+guint32
+gdk_time_get (void)
+{
+  guint32 milliseconds;
+  guint32 end = GetTickCount ();
+
+  if (end < start)
+    milliseconds = 0xFFFFFFFF - (start - end) + 1;
+  else
+    milliseconds = end - start;
+
+  return milliseconds;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_timer_get
+ *
+ *   Returns the current timer.
+ *
+ * Arguments:
+ *
+ * Results:
+ *   Returns the current timer interval. This interval is
+ *   in units of milliseconds.
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+guint32
+gdk_timer_get (void)
+{
+  return timer_val;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_timer_set
+ *
+ *   Sets the timer interval.
+ *
+ * Arguments:
+ *   "milliseconds" is the new value for the timer.
+ *
+ * Results:
+ *
+ * Side effects:
+ *   Calls to "gdk_event_get" will last for a maximum
+ *   of time of "milliseconds". However, a value of 0
+ *   milliseconds will cause "gdk_event_get" to block
+ *   indefinately until an event is received.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_timer_set (guint32 milliseconds)
+{
+  timer_val = milliseconds;
+#ifdef USE_PEEKNAMEDPIPE
+  /* When using PeekNamedPipe, can't have too long timeouts.
+   */
+  if (timer_val > 10)
+    timer_val = 10;
+  else if (timer_val == 0)
+    timer_val = 0;
+#endif
+}
+
+void
+gdk_timer_enable (void)
+{
+  timerp = TRUE;
+}
+
+void
+gdk_timer_disable (void)
+{
+#ifdef USE_PEEKNAMEDPIPE
+  /* Can't disable timeouts when using PeekNamedPipe */
+#else
+  timerp = FALSE;
+#endif
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_screen_width
+ *
+ *   Return the width of the screen.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_screen_width (void)
+{
+  gint return_val;
+  
+  return_val = gdk_root_parent.width;
+
+  return return_val;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_screen_height
+ *
+ *   Return the height of the screen.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_screen_height (void)
+{
+  gint return_val;
+  
+  return_val = gdk_root_parent.height;
+
+  return return_val;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_screen_width_mm
+ *
+ *   Return the width of the screen in millimetres.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_screen_width_mm (void)
+{
+  HDC hdc;
+  gint return_val;
+
+  hdc = GetDC (NULL);
+  return_val = GetDeviceCaps (hdc, HORZSIZE);
+  ReleaseDC (NULL, hdc);
+
+  return return_val;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_screen_height
+ *
+ *   Return the height of the screen in millimetres.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+gint
+gdk_screen_height_mm (void)
+{
+  HDC hdc;
+  gint return_val;
+
+  hdc = GetDC (NULL);
+  return_val = GetDeviceCaps (hdc, VERTSIZE);
+  ReleaseDC (NULL, hdc);
+  
+  return return_val;
+}
+
+void
+gdk_key_repeat_disable (void)
+{
+  /* XXX */
+}
+
+void
+gdk_key_repeat_restore (void)
+{
+  /* XXX */
+}
+
+
+/*
+ *--------------------------------------------------------------
+ * gdk_flush
+ *
+ *   Flushes the Xlib output buffer and then waits
+ *   until all requests have been received and processed
+ *   by the X server. The only real use for this function
+ *   is in dealing with XShm.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+gdk_flush (void)
+{
+  GdiFlush ();
+}
+
+void
+gdk_beep (void)
+{
+  Beep(1000, 50);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gdk_exit_func
+ *
+ *   This is the "atexit" function that makes sure the
+ *   library gets a chance to cleanup.
+ *
+ * Arguments:
+ *
+ * Results:
+ *
+ * Side effects:
+ *   The library is un-initialized and the program exits.
+ *
+ *--------------------------------------------------------------
+ */
+
+static void
+gdk_exit_func (void)
+{
+  static gboolean in_gdk_exit_func = FALSE;
+  
+  GDK_NOTE (MISC, g_print ("gdk_exit_func\n"));
+  /* This is to avoid an infinite loop if a program segfaults in
+     an atexit() handler (and yes, it does happen, especially if a program
+     has trounced over memory too badly for even g_message to work) */
+  if (in_gdk_exit_func == TRUE)
+    return;
+  in_gdk_exit_func = TRUE;
+  
+  if (gdk_initialized)
+    {
+      gdk_image_exit ();
+      gdk_input_exit ();
+      gdk_key_repeat_restore ();
+      gdk_dnd_exit ();
+      gdk_initialized = 0;
+    }
+}
+
+gchar *
+gdk_get_display(void)
+{
+  return "local:";
+}
+
+/*************************************************************
+ * gdk_error_trap_push:
+ *     Push an error trap. X errors will be trapped until
+ *     the corresponding gdk_error_pop(), which will return
+ *     the error code, if any.
+ *   arguments:
+ *     
+ *   results:
+ *************************************************************/
+
+void
+gdk_error_trap_push (void)
+{
+  /* ??? */
+}
+
+/*************************************************************
+ * gdk_error_trap_pop:
+ *     Pop an error trap added with gdk_error_push()
+ *   arguments:
+ *     
+ *   results:
+ *     0, if no error occured, otherwise the error code.
+ *************************************************************/
+
+gint
+gdk_error_trap_pop (void)
+{
+  /* ??? */
+  return 0;
+}
+
+static void
+gdkx_XConvertCase (KeySym symbol,
+                  KeySym *lower,
+                  KeySym *upper)
+{
+  register KeySym sym = symbol;
+  
+  g_return_if_fail (lower != NULL);
+  g_return_if_fail (upper != NULL);
+  
+  *lower = sym;
+  *upper = sym;
+  
+  switch (sym >> 8)
+    {
+#if    defined (GDK_A) && defined (GDK_Ooblique)
+    case 0: /* Latin 1 */
+      if ((sym >= GDK_A) && (sym <= GDK_Z))
+       *lower += (GDK_a - GDK_A);
+      else if ((sym >= GDK_a) && (sym <= GDK_z))
+       *upper -= (GDK_a - GDK_A);
+      else if ((sym >= GDK_Agrave) && (sym <= GDK_Odiaeresis))
+       *lower += (GDK_agrave - GDK_Agrave);
+      else if ((sym >= GDK_agrave) && (sym <= GDK_odiaeresis))
+       *upper -= (GDK_agrave - GDK_Agrave);
+      else if ((sym >= GDK_Ooblique) && (sym <= GDK_Thorn))
+       *lower += (GDK_oslash - GDK_Ooblique);
+      else if ((sym >= GDK_oslash) && (sym <= GDK_thorn))
+       *upper -= (GDK_oslash - GDK_Ooblique);
+      break;
+#endif /* LATIN1 */
+      
+#if    defined (GDK_Aogonek) && defined (GDK_tcedilla)
+    case 1: /* Latin 2 */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (sym == GDK_Aogonek)
+       *lower = GDK_aogonek;
+      else if (sym >= GDK_Lstroke && sym <= GDK_Sacute)
+       *lower += (GDK_lstroke - GDK_Lstroke);
+      else if (sym >= GDK_Scaron && sym <= GDK_Zacute)
+       *lower += (GDK_scaron - GDK_Scaron);
+      else if (sym >= GDK_Zcaron && sym <= GDK_Zabovedot)
+       *lower += (GDK_zcaron - GDK_Zcaron);
+      else if (sym == GDK_aogonek)
+       *upper = GDK_Aogonek;
+      else if (sym >= GDK_lstroke && sym <= GDK_sacute)
+       *upper -= (GDK_lstroke - GDK_Lstroke);
+      else if (sym >= GDK_scaron && sym <= GDK_zacute)
+       *upper -= (GDK_scaron - GDK_Scaron);
+      else if (sym >= GDK_zcaron && sym <= GDK_zabovedot)
+       *upper -= (GDK_zcaron - GDK_Zcaron);
+      else if (sym >= GDK_Racute && sym <= GDK_Tcedilla)
+       *lower += (GDK_racute - GDK_Racute);
+      else if (sym >= GDK_racute && sym <= GDK_tcedilla)
+       *upper -= (GDK_racute - GDK_Racute);
+      break;
+#endif /* LATIN2 */
+      
+#if    defined (GDK_Hstroke) && defined (GDK_Cabovedot)
+    case 2: /* Latin 3 */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (sym >= GDK_Hstroke && sym <= GDK_Hcircumflex)
+       *lower += (GDK_hstroke - GDK_Hstroke);
+      else if (sym >= GDK_Gbreve && sym <= GDK_Jcircumflex)
+       *lower += (GDK_gbreve - GDK_Gbreve);
+      else if (sym >= GDK_hstroke && sym <= GDK_hcircumflex)
+       *upper -= (GDK_hstroke - GDK_Hstroke);
+      else if (sym >= GDK_gbreve && sym <= GDK_jcircumflex)
+       *upper -= (GDK_gbreve - GDK_Gbreve);
+      else if (sym >= GDK_Cabovedot && sym <= GDK_Scircumflex)
+       *lower += (GDK_cabovedot - GDK_Cabovedot);
+      else if (sym >= GDK_cabovedot && sym <= GDK_scircumflex)
+       *upper -= (GDK_cabovedot - GDK_Cabovedot);
+      break;
+#endif /* LATIN3 */
+      
+#if    defined (GDK_Rcedilla) && defined (GDK_Amacron)
+    case 3: /* Latin 4 */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (sym >= GDK_Rcedilla && sym <= GDK_Tslash)
+       *lower += (GDK_rcedilla - GDK_Rcedilla);
+      else if (sym >= GDK_rcedilla && sym <= GDK_tslash)
+       *upper -= (GDK_rcedilla - GDK_Rcedilla);
+      else if (sym == GDK_ENG)
+       *lower = GDK_eng;
+      else if (sym == GDK_eng)
+       *upper = GDK_ENG;
+      else if (sym >= GDK_Amacron && sym <= GDK_Umacron)
+       *lower += (GDK_amacron - GDK_Amacron);
+      else if (sym >= GDK_amacron && sym <= GDK_umacron)
+       *upper -= (GDK_amacron - GDK_Amacron);
+      break;
+#endif /* LATIN4 */
+      
+#if    defined (GDK_Serbian_DJE) && defined (GDK_Cyrillic_yu)
+    case 6: /* Cyrillic */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (sym >= GDK_Serbian_DJE && sym <= GDK_Serbian_DZE)
+       *lower -= (GDK_Serbian_DJE - GDK_Serbian_dje);
+      else if (sym >= GDK_Serbian_dje && sym <= GDK_Serbian_dze)
+       *upper += (GDK_Serbian_DJE - GDK_Serbian_dje);
+      else if (sym >= GDK_Cyrillic_YU && sym <= GDK_Cyrillic_HARDSIGN)
+       *lower -= (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
+      else if (sym >= GDK_Cyrillic_yu && sym <= GDK_Cyrillic_hardsign)
+       *upper += (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
+      break;
+#endif /* CYRILLIC */
+
+#if    defined (GDK_Greek_ALPHAaccent) && defined (GDK_Greek_finalsmallsigma)
+    case 7: /* Greek */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (sym >= GDK_Greek_ALPHAaccent && sym <= GDK_Greek_OMEGAaccent)
+       *lower += (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
+      else if (sym >= GDK_Greek_alphaaccent && sym <= GDK_Greek_omegaaccent &&
+              sym != GDK_Greek_iotaaccentdieresis &&
+              sym != GDK_Greek_upsilonaccentdieresis)
+       *upper -= (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
+      else if (sym >= GDK_Greek_ALPHA && sym <= GDK_Greek_OMEGA)
+       *lower += (GDK_Greek_alpha - GDK_Greek_ALPHA);
+      else if (sym >= GDK_Greek_alpha && sym <= GDK_Greek_omega &&
+              sym != GDK_Greek_finalsmallsigma)
+       *upper -= (GDK_Greek_alpha - GDK_Greek_ALPHA);
+      break;
+#endif /* GREEK */
+    }
+}
+
+static struct gdk_key {
+  guint keyval;
+  const char *name;
+} gdk_keys_by_keyval[] = {
+  { 0x000020, "space" },
+  { 0x000021, "exclam" },
+  { 0x000022, "quotedbl" },
+  { 0x000023, "numbersign" },
+  { 0x000024, "dollar" },
+  { 0x000025, "percent" },
+  { 0x000026, "ampersand" },
+  { 0x000027, "apostrophe" },
+  { 0x000027, "quoteright" },
+  { 0x000028, "parenleft" },
+  { 0x000029, "parenright" },
+  { 0x00002a, "asterisk" },
+  { 0x00002b, "plus" },
+  { 0x00002c, "comma" },
+  { 0x00002d, "minus" },
+  { 0x00002e, "period" },
+  { 0x00002f, "slash" },
+  { 0x000030, "0" },
+  { 0x000031, "1" },
+  { 0x000032, "2" },
+  { 0x000033, "3" },
+  { 0x000034, "4" },
+  { 0x000035, "5" },
+  { 0x000036, "6" },
+  { 0x000037, "7" },
+  { 0x000038, "8" },
+  { 0x000039, "9" },
+  { 0x00003a, "colon" },
+  { 0x00003b, "semicolon" },
+  { 0x00003c, "less" },
+  { 0x00003d, "equal" },
+  { 0x00003e, "greater" },
+  { 0x00003f, "question" },
+  { 0x000040, "at" },
+  { 0x000041, "A" },
+  { 0x000042, "B" },
+  { 0x000043, "C" },
+  { 0x000044, "D" },
+  { 0x000045, "E" },
+  { 0x000046, "F" },
+  { 0x000047, "G" },
+  { 0x000048, "H" },
+  { 0x000049, "I" },
+  { 0x00004a, "J" },
+  { 0x00004b, "K" },
+  { 0x00004c, "L" },
+  { 0x00004d, "M" },
+  { 0x00004e, "N" },
+  { 0x00004f, "O" },
+  { 0x000050, "P" },
+  { 0x000051, "Q" },
+  { 0x000052, "R" },
+  { 0x000053, "S" },
+  { 0x000054, "T" },
+  { 0x000055, "U" },
+  { 0x000056, "V" },
+  { 0x000057, "W" },
+  { 0x000058, "X" },
+  { 0x000059, "Y" },
+  { 0x00005a, "Z" },
+  { 0x00005b, "bracketleft" },
+  { 0x00005c, "backslash" },
+  { 0x00005d, "bracketright" },
+  { 0x00005e, "asciicircum" },
+  { 0x00005f, "underscore" },
+  { 0x000060, "grave" },
+  { 0x000060, "quoteleft" },
+  { 0x000061, "a" },
+  { 0x000062, "b" },
+  { 0x000063, "c" },
+  { 0x000064, "d" },
+  { 0x000065, "e" },
+  { 0x000066, "f" },
+  { 0x000067, "g" },
+  { 0x000068, "h" },
+  { 0x000069, "i" },
+  { 0x00006a, "j" },
+  { 0x00006b, "k" },
+  { 0x00006c, "l" },
+  { 0x00006d, "m" },
+  { 0x00006e, "n" },
+  { 0x00006f, "o" },
+  { 0x000070, "p" },
+  { 0x000071, "q" },
+  { 0x000072, "r" },
+  { 0x000073, "s" },
+  { 0x000074, "t" },
+  { 0x000075, "u" },
+  { 0x000076, "v" },
+  { 0x000077, "w" },
+  { 0x000078, "x" },
+  { 0x000079, "y" },
+  { 0x00007a, "z" },
+  { 0x00007b, "braceleft" },
+  { 0x00007c, "bar" },
+  { 0x00007d, "braceright" },
+  { 0x00007e, "asciitilde" },
+  { 0x0000a0, "nobreakspace" },
+  { 0x0000a1, "exclamdown" },
+  { 0x0000a2, "cent" },
+  { 0x0000a3, "sterling" },
+  { 0x0000a4, "currency" },
+  { 0x0000a5, "yen" },
+  { 0x0000a6, "brokenbar" },
+  { 0x0000a7, "section" },
+  { 0x0000a8, "diaeresis" },
+  { 0x0000a9, "copyright" },
+  { 0x0000aa, "ordfeminine" },
+  { 0x0000ab, "guillemotleft" },
+  { 0x0000ac, "notsign" },
+  { 0x0000ad, "hyphen" },
+  { 0x0000ae, "registered" },
+  { 0x0000af, "macron" },
+  { 0x0000b0, "degree" },
+  { 0x0000b1, "plusminus" },
+  { 0x0000b2, "twosuperior" },
+  { 0x0000b3, "threesuperior" },
+  { 0x0000b4, "acute" },
+  { 0x0000b5, "mu" },
+  { 0x0000b6, "paragraph" },
+  { 0x0000b7, "periodcentered" },
+  { 0x0000b8, "cedilla" },
+  { 0x0000b9, "onesuperior" },
+  { 0x0000ba, "masculine" },
+  { 0x0000bb, "guillemotright" },
+  { 0x0000bc, "onequarter" },
+  { 0x0000bd, "onehalf" },
+  { 0x0000be, "threequarters" },
+  { 0x0000bf, "questiondown" },
+  { 0x0000c0, "Agrave" },
+  { 0x0000c1, "Aacute" },
+  { 0x0000c2, "Acircumflex" },
+  { 0x0000c3, "Atilde" },
+  { 0x0000c4, "Adiaeresis" },
+  { 0x0000c5, "Aring" },
+  { 0x0000c6, "AE" },
+  { 0x0000c7, "Ccedilla" },
+  { 0x0000c8, "Egrave" },
+  { 0x0000c9, "Eacute" },
+  { 0x0000ca, "Ecircumflex" },
+  { 0x0000cb, "Ediaeresis" },
+  { 0x0000cc, "Igrave" },
+  { 0x0000cd, "Iacute" },
+  { 0x0000ce, "Icircumflex" },
+  { 0x0000cf, "Idiaeresis" },
+  { 0x0000d0, "ETH" },
+  { 0x0000d0, "Eth" },
+  { 0x0000d1, "Ntilde" },
+  { 0x0000d2, "Ograve" },
+  { 0x0000d3, "Oacute" },
+  { 0x0000d4, "Ocircumflex" },
+  { 0x0000d5, "Otilde" },
+  { 0x0000d6, "Odiaeresis" },
+  { 0x0000d7, "multiply" },
+  { 0x0000d8, "Ooblique" },
+  { 0x0000d9, "Ugrave" },
+  { 0x0000da, "Uacute" },
+  { 0x0000db, "Ucircumflex" },
+  { 0x0000dc, "Udiaeresis" },
+  { 0x0000dd, "Yacute" },
+  { 0x0000de, "THORN" },
+  { 0x0000de, "Thorn" },
+  { 0x0000df, "ssharp" },
+  { 0x0000e0, "agrave" },
+  { 0x0000e1, "aacute" },
+  { 0x0000e2, "acircumflex" },
+  { 0x0000e3, "atilde" },
+  { 0x0000e4, "adiaeresis" },
+  { 0x0000e5, "aring" },
+  { 0x0000e6, "ae" },
+  { 0x0000e7, "ccedilla" },
+  { 0x0000e8, "egrave" },
+  { 0x0000e9, "eacute" },
+  { 0x0000ea, "ecircumflex" },
+  { 0x0000eb, "ediaeresis" },
+  { 0x0000ec, "igrave" },
+  { 0x0000ed, "iacute" },
+  { 0x0000ee, "icircumflex" },
+  { 0x0000ef, "idiaeresis" },
+  { 0x0000f0, "eth" },
+  { 0x0000f1, "ntilde" },
+  { 0x0000f2, "ograve" },
+  { 0x0000f3, "oacute" },
+  { 0x0000f4, "ocircumflex" },
+  { 0x0000f5, "otilde" },
+  { 0x0000f6, "odiaeresis" },
+  { 0x0000f7, "division" },
+  { 0x0000f8, "oslash" },
+  { 0x0000f9, "ugrave" },
+  { 0x0000fa, "uacute" },
+  { 0x0000fb, "ucircumflex" },
+  { 0x0000fc, "udiaeresis" },
+  { 0x0000fd, "yacute" },
+  { 0x0000fe, "thorn" },
+  { 0x0000ff, "ydiaeresis" },
+  { 0x0001a1, "Aogonek" },
+  { 0x0001a2, "breve" },
+  { 0x0001a3, "Lstroke" },
+  { 0x0001a5, "Lcaron" },
+  { 0x0001a6, "Sacute" },
+  { 0x0001a9, "Scaron" },
+  { 0x0001aa, "Scedilla" },
+  { 0x0001ab, "Tcaron" },
+  { 0x0001ac, "Zacute" },
+  { 0x0001ae, "Zcaron" },
+  { 0x0001af, "Zabovedot" },
+  { 0x0001b1, "aogonek" },
+  { 0x0001b2, "ogonek" },
+  { 0x0001b3, "lstroke" },
+  { 0x0001b5, "lcaron" },
+  { 0x0001b6, "sacute" },
+  { 0x0001b7, "caron" },
+  { 0x0001b9, "scaron" },
+  { 0x0001ba, "scedilla" },
+  { 0x0001bb, "tcaron" },
+  { 0x0001bc, "zacute" },
+  { 0x0001bd, "doubleacute" },
+  { 0x0001be, "zcaron" },
+  { 0x0001bf, "zabovedot" },
+  { 0x0001c0, "Racute" },
+  { 0x0001c3, "Abreve" },
+  { 0x0001c5, "Lacute" },
+  { 0x0001c6, "Cacute" },
+  { 0x0001c8, "Ccaron" },
+  { 0x0001ca, "Eogonek" },
+  { 0x0001cc, "Ecaron" },
+  { 0x0001cf, "Dcaron" },
+  { 0x0001d0, "Dstroke" },
+  { 0x0001d1, "Nacute" },
+  { 0x0001d2, "Ncaron" },
+  { 0x0001d5, "Odoubleacute" },
+  { 0x0001d8, "Rcaron" },
+  { 0x0001d9, "Uring" },
+  { 0x0001db, "Udoubleacute" },
+  { 0x0001de, "Tcedilla" },
+  { 0x0001e0, "racute" },
+  { 0x0001e3, "abreve" },
+  { 0x0001e5, "lacute" },
+  { 0x0001e6, "cacute" },
+  { 0x0001e8, "ccaron" },
+  { 0x0001ea, "eogonek" },
+  { 0x0001ec, "ecaron" },
+  { 0x0001ef, "dcaron" },
+  { 0x0001f0, "dstroke" },
+  { 0x0001f1, "nacute" },
+  { 0x0001f2, "ncaron" },
+  { 0x0001f5, "odoubleacute" },
+  { 0x0001f8, "rcaron" },
+  { 0x0001f9, "uring" },
+  { 0x0001fb, "udoubleacute" },
+  { 0x0001fe, "tcedilla" },
+  { 0x0001ff, "abovedot" },
+  { 0x0002a1, "Hstroke" },
+  { 0x0002a6, "Hcircumflex" },
+  { 0x0002a9, "Iabovedot" },
+  { 0x0002ab, "Gbreve" },
+  { 0x0002ac, "Jcircumflex" },
+  { 0x0002b1, "hstroke" },
+  { 0x0002b6, "hcircumflex" },
+  { 0x0002b9, "idotless" },
+  { 0x0002bb, "gbreve" },
+  { 0x0002bc, "jcircumflex" },
+  { 0x0002c5, "Cabovedot" },
+  { 0x0002c6, "Ccircumflex" },
+  { 0x0002d5, "Gabovedot" },
+  { 0x0002d8, "Gcircumflex" },
+  { 0x0002dd, "Ubreve" },
+  { 0x0002de, "Scircumflex" },
+  { 0x0002e5, "cabovedot" },
+  { 0x0002e6, "ccircumflex" },
+  { 0x0002f5, "gabovedot" },
+  { 0x0002f8, "gcircumflex" },
+  { 0x0002fd, "ubreve" },
+  { 0x0002fe, "scircumflex" },
+  { 0x0003a2, "kappa" },
+  { 0x0003a2, "kra" },
+  { 0x0003a3, "Rcedilla" },
+  { 0x0003a5, "Itilde" },
+  { 0x0003a6, "Lcedilla" },
+  { 0x0003aa, "Emacron" },
+  { 0x0003ab, "Gcedilla" },
+  { 0x0003ac, "Tslash" },
+  { 0x0003b3, "rcedilla" },
+  { 0x0003b5, "itilde" },
+  { 0x0003b6, "lcedilla" },
+  { 0x0003ba, "emacron" },
+  { 0x0003bb, "gcedilla" },
+  { 0x0003bc, "tslash" },
+  { 0x0003bd, "ENG" },
+  { 0x0003bf, "eng" },
+  { 0x0003c0, "Amacron" },
+  { 0x0003c7, "Iogonek" },
+  { 0x0003cc, "Eabovedot" },
+  { 0x0003cf, "Imacron" },
+  { 0x0003d1, "Ncedilla" },
+  { 0x0003d2, "Omacron" },
+  { 0x0003d3, "Kcedilla" },
+  { 0x0003d9, "Uogonek" },
+  { 0x0003dd, "Utilde" },
+  { 0x0003de, "Umacron" },
+  { 0x0003e0, "amacron" },
+  { 0x0003e7, "iogonek" },
+  { 0x0003ec, "eabovedot" },
+  { 0x0003ef, "imacron" },
+  { 0x0003f1, "ncedilla" },
+  { 0x0003f2, "omacron" },
+  { 0x0003f3, "kcedilla" },
+  { 0x0003f9, "uogonek" },
+  { 0x0003fd, "utilde" },
+  { 0x0003fe, "umacron" },
+  { 0x00047e, "overline" },
+  { 0x0004a1, "kana_fullstop" },
+  { 0x0004a2, "kana_openingbracket" },
+  { 0x0004a3, "kana_closingbracket" },
+  { 0x0004a4, "kana_comma" },
+  { 0x0004a5, "kana_conjunctive" },
+  { 0x0004a5, "kana_middledot" },
+  { 0x0004a6, "kana_WO" },
+  { 0x0004a7, "kana_a" },
+  { 0x0004a8, "kana_i" },
+  { 0x0004a9, "kana_u" },
+  { 0x0004aa, "kana_e" },
+  { 0x0004ab, "kana_o" },
+  { 0x0004ac, "kana_ya" },
+  { 0x0004ad, "kana_yu" },
+  { 0x0004ae, "kana_yo" },
+  { 0x0004af, "kana_tsu" },
+  { 0x0004af, "kana_tu" },
+  { 0x0004b0, "prolongedsound" },
+  { 0x0004b1, "kana_A" },
+  { 0x0004b2, "kana_I" },
+  { 0x0004b3, "kana_U" },
+  { 0x0004b4, "kana_E" },
+  { 0x0004b5, "kana_O" },
+  { 0x0004b6, "kana_KA" },
+  { 0x0004b7, "kana_KI" },
+  { 0x0004b8, "kana_KU" },
+  { 0x0004b9, "kana_KE" },
+  { 0x0004ba, "kana_KO" },
+  { 0x0004bb, "kana_SA" },
+  { 0x0004bc, "kana_SHI" },
+  { 0x0004bd, "kana_SU" },
+  { 0x0004be, "kana_SE" },
+  { 0x0004bf, "kana_SO" },
+  { 0x0004c0, "kana_TA" },
+  { 0x0004c1, "kana_CHI" },
+  { 0x0004c1, "kana_TI" },
+  { 0x0004c2, "kana_TSU" },
+  { 0x0004c2, "kana_TU" },
+  { 0x0004c3, "kana_TE" },
+  { 0x0004c4, "kana_TO" },
+  { 0x0004c5, "kana_NA" },
+  { 0x0004c6, "kana_NI" },
+  { 0x0004c7, "kana_NU" },
+  { 0x0004c8, "kana_NE" },
+  { 0x0004c9, "kana_NO" },
+  { 0x0004ca, "kana_HA" },
+  { 0x0004cb, "kana_HI" },
+  { 0x0004cc, "kana_FU" },
+  { 0x0004cc, "kana_HU" },
+  { 0x0004cd, "kana_HE" },
+  { 0x0004ce, "kana_HO" },
+  { 0x0004cf, "kana_MA" },
+  { 0x0004d0, "kana_MI" },
+  { 0x0004d1, "kana_MU" },
+  { 0x0004d2, "kana_ME" },
+  { 0x0004d3, "kana_MO" },
+  { 0x0004d4, "kana_YA" },
+  { 0x0004d5, "kana_YU" },
+  { 0x0004d6, "kana_YO" },
+  { 0x0004d7, "kana_RA" },
+  { 0x0004d8, "kana_RI" },
+  { 0x0004d9, "kana_RU" },
+  { 0x0004da, "kana_RE" },
+  { 0x0004db, "kana_RO" },
+  { 0x0004dc, "kana_WA" },
+  { 0x0004dd, "kana_N" },
+  { 0x0004de, "voicedsound" },
+  { 0x0004df, "semivoicedsound" },
+  { 0x0005ac, "Arabic_comma" },
+  { 0x0005bb, "Arabic_semicolon" },
+  { 0x0005bf, "Arabic_question_mark" },
+  { 0x0005c1, "Arabic_hamza" },
+  { 0x0005c2, "Arabic_maddaonalef" },
+  { 0x0005c3, "Arabic_hamzaonalef" },
+  { 0x0005c4, "Arabic_hamzaonwaw" },
+  { 0x0005c5, "Arabic_hamzaunderalef" },
+  { 0x0005c6, "Arabic_hamzaonyeh" },
+  { 0x0005c7, "Arabic_alef" },
+  { 0x0005c8, "Arabic_beh" },
+  { 0x0005c9, "Arabic_tehmarbuta" },
+  { 0x0005ca, "Arabic_teh" },
+  { 0x0005cb, "Arabic_theh" },
+  { 0x0005cc, "Arabic_jeem" },
+  { 0x0005cd, "Arabic_hah" },
+  { 0x0005ce, "Arabic_khah" },
+  { 0x0005cf, "Arabic_dal" },
+  { 0x0005d0, "Arabic_thal" },
+  { 0x0005d1, "Arabic_ra" },
+  { 0x0005d2, "Arabic_zain" },
+  { 0x0005d3, "Arabic_seen" },
+  { 0x0005d4, "Arabic_sheen" },
+  { 0x0005d5, "Arabic_sad" },
+  { 0x0005d6, "Arabic_dad" },
+  { 0x0005d7, "Arabic_tah" },
+  { 0x0005d8, "Arabic_zah" },
+  { 0x0005d9, "Arabic_ain" },
+  { 0x0005da, "Arabic_ghain" },
+  { 0x0005e0, "Arabic_tatweel" },
+  { 0x0005e1, "Arabic_feh" },
+  { 0x0005e2, "Arabic_qaf" },
+  { 0x0005e3, "Arabic_kaf" },
+  { 0x0005e4, "Arabic_lam" },
+  { 0x0005e5, "Arabic_meem" },
+  { 0x0005e6, "Arabic_noon" },
+  { 0x0005e7, "Arabic_ha" },
+  { 0x0005e7, "Arabic_heh" },
+  { 0x0005e8, "Arabic_waw" },
+  { 0x0005e9, "Arabic_alefmaksura" },
+  { 0x0005ea, "Arabic_yeh" },
+  { 0x0005eb, "Arabic_fathatan" },
+  { 0x0005ec, "Arabic_dammatan" },
+  { 0x0005ed, "Arabic_kasratan" },
+  { 0x0005ee, "Arabic_fatha" },
+  { 0x0005ef, "Arabic_damma" },
+  { 0x0005f0, "Arabic_kasra" },
+  { 0x0005f1, "Arabic_shadda" },
+  { 0x0005f2, "Arabic_sukun" },
+  { 0x0006a1, "Serbian_dje" },
+  { 0x0006a2, "Macedonia_gje" },
+  { 0x0006a3, "Cyrillic_io" },
+  { 0x0006a4, "Ukrainian_ie" },
+  { 0x0006a4, "Ukranian_je" },
+  { 0x0006a5, "Macedonia_dse" },
+  { 0x0006a6, "Ukrainian_i" },
+  { 0x0006a6, "Ukranian_i" },
+  { 0x0006a7, "Ukrainian_yi" },
+  { 0x0006a7, "Ukranian_yi" },
+  { 0x0006a8, "Cyrillic_je" },
+  { 0x0006a8, "Serbian_je" },
+  { 0x0006a9, "Cyrillic_lje" },
+  { 0x0006a9, "Serbian_lje" },
+  { 0x0006aa, "Cyrillic_nje" },
+  { 0x0006aa, "Serbian_nje" },
+  { 0x0006ab, "Serbian_tshe" },
+  { 0x0006ac, "Macedonia_kje" },
+  { 0x0006ae, "Byelorussian_shortu" },
+  { 0x0006af, "Cyrillic_dzhe" },
+  { 0x0006af, "Serbian_dze" },
+  { 0x0006b0, "numerosign" },
+  { 0x0006b1, "Serbian_DJE" },
+  { 0x0006b2, "Macedonia_GJE" },
+  { 0x0006b3, "Cyrillic_IO" },
+  { 0x0006b4, "Ukrainian_IE" },
+  { 0x0006b4, "Ukranian_JE" },
+  { 0x0006b5, "Macedonia_DSE" },
+  { 0x0006b6, "Ukrainian_I" },
+  { 0x0006b6, "Ukranian_I" },
+  { 0x0006b7, "Ukrainian_YI" },
+  { 0x0006b7, "Ukranian_YI" },
+  { 0x0006b8, "Cyrillic_JE" },
+  { 0x0006b8, "Serbian_JE" },
+  { 0x0006b9, "Cyrillic_LJE" },
+  { 0x0006b9, "Serbian_LJE" },
+  { 0x0006ba, "Cyrillic_NJE" },
+  { 0x0006ba, "Serbian_NJE" },
+  { 0x0006bb, "Serbian_TSHE" },
+  { 0x0006bc, "Macedonia_KJE" },
+  { 0x0006be, "Byelorussian_SHORTU" },
+  { 0x0006bf, "Cyrillic_DZHE" },
+  { 0x0006bf, "Serbian_DZE" },
+  { 0x0006c0, "Cyrillic_yu" },
+  { 0x0006c1, "Cyrillic_a" },
+  { 0x0006c2, "Cyrillic_be" },
+  { 0x0006c3, "Cyrillic_tse" },
+  { 0x0006c4, "Cyrillic_de" },
+  { 0x0006c5, "Cyrillic_ie" },
+  { 0x0006c6, "Cyrillic_ef" },
+  { 0x0006c7, "Cyrillic_ghe" },
+  { 0x0006c8, "Cyrillic_ha" },
+  { 0x0006c9, "Cyrillic_i" },
+  { 0x0006ca, "Cyrillic_shorti" },
+  { 0x0006cb, "Cyrillic_ka" },
+  { 0x0006cc, "Cyrillic_el" },
+  { 0x0006cd, "Cyrillic_em" },
+  { 0x0006ce, "Cyrillic_en" },
+  { 0x0006cf, "Cyrillic_o" },
+  { 0x0006d0, "Cyrillic_pe" },
+  { 0x0006d1, "Cyrillic_ya" },
+  { 0x0006d2, "Cyrillic_er" },
+  { 0x0006d3, "Cyrillic_es" },
+  { 0x0006d4, "Cyrillic_te" },
+  { 0x0006d5, "Cyrillic_u" },
+  { 0x0006d6, "Cyrillic_zhe" },
+  { 0x0006d7, "Cyrillic_ve" },
+  { 0x0006d8, "Cyrillic_softsign" },
+  { 0x0006d9, "Cyrillic_yeru" },
+  { 0x0006da, "Cyrillic_ze" },
+  { 0x0006db, "Cyrillic_sha" },
+  { 0x0006dc, "Cyrillic_e" },
+  { 0x0006dd, "Cyrillic_shcha" },
+  { 0x0006de, "Cyrillic_che" },
+  { 0x0006df, "Cyrillic_hardsign" },
+  { 0x0006e0, "Cyrillic_YU" },
+  { 0x0006e1, "Cyrillic_A" },
+  { 0x0006e2, "Cyrillic_BE" },
+  { 0x0006e3, "Cyrillic_TSE" },
+  { 0x0006e4, "Cyrillic_DE" },
+  { 0x0006e5, "Cyrillic_IE" },
+  { 0x0006e6, "Cyrillic_EF" },
+  { 0x0006e7, "Cyrillic_GHE" },
+  { 0x0006e8, "Cyrillic_HA" },
+  { 0x0006e9, "Cyrillic_I" },
+  { 0x0006ea, "Cyrillic_SHORTI" },
+  { 0x0006eb, "Cyrillic_KA" },
+  { 0x0006ec, "Cyrillic_EL" },
+  { 0x0006ed, "Cyrillic_EM" },
+  { 0x0006ee, "Cyrillic_EN" },
+  { 0x0006ef, "Cyrillic_O" },
+  { 0x0006f0, "Cyrillic_PE" },
+  { 0x0006f1, "Cyrillic_YA" },
+  { 0x0006f2, "Cyrillic_ER" },
+  { 0x0006f3, "Cyrillic_ES" },
+  { 0x0006f4, "Cyrillic_TE" },
+  { 0x0006f5, "Cyrillic_U" },
+  { 0x0006f6, "Cyrillic_ZHE" },
+  { 0x0006f7, "Cyrillic_VE" },
+  { 0x0006f8, "Cyrillic_SOFTSIGN" },
+  { 0x0006f9, "Cyrillic_YERU" },
+  { 0x0006fa, "Cyrillic_ZE" },
+  { 0x0006fb, "Cyrillic_SHA" },
+  { 0x0006fc, "Cyrillic_E" },
+  { 0x0006fd, "Cyrillic_SHCHA" },
+  { 0x0006fe, "Cyrillic_CHE" },
+  { 0x0006ff, "Cyrillic_HARDSIGN" },
+  { 0x0007a1, "Greek_ALPHAaccent" },
+  { 0x0007a2, "Greek_EPSILONaccent" },
+  { 0x0007a3, "Greek_ETAaccent" },
+  { 0x0007a4, "Greek_IOTAaccent" },
+  { 0x0007a5, "Greek_IOTAdiaeresis" },
+  { 0x0007a7, "Greek_OMICRONaccent" },
+  { 0x0007a8, "Greek_UPSILONaccent" },
+  { 0x0007a9, "Greek_UPSILONdieresis" },
+  { 0x0007ab, "Greek_OMEGAaccent" },
+  { 0x0007ae, "Greek_accentdieresis" },
+  { 0x0007af, "Greek_horizbar" },
+  { 0x0007b1, "Greek_alphaaccent" },
+  { 0x0007b2, "Greek_epsilonaccent" },
+  { 0x0007b3, "Greek_etaaccent" },
+  { 0x0007b4, "Greek_iotaaccent" },
+  { 0x0007b5, "Greek_iotadieresis" },
+  { 0x0007b6, "Greek_iotaaccentdieresis" },
+  { 0x0007b7, "Greek_omicronaccent" },
+  { 0x0007b8, "Greek_upsilonaccent" },
+  { 0x0007b9, "Greek_upsilondieresis" },
+  { 0x0007ba, "Greek_upsilonaccentdieresis" },
+  { 0x0007bb, "Greek_omegaaccent" },
+  { 0x0007c1, "Greek_ALPHA" },
+  { 0x0007c2, "Greek_BETA" },
+  { 0x0007c3, "Greek_GAMMA" },
+  { 0x0007c4, "Greek_DELTA" },
+  { 0x0007c5, "Greek_EPSILON" },
+  { 0x0007c6, "Greek_ZETA" },
+  { 0x0007c7, "Greek_ETA" },
+  { 0x0007c8, "Greek_THETA" },
+  { 0x0007c9, "Greek_IOTA" },
+  { 0x0007ca, "Greek_KAPPA" },
+  { 0x0007cb, "Greek_LAMBDA" },
+  { 0x0007cb, "Greek_LAMDA" },
+  { 0x0007cc, "Greek_MU" },
+  { 0x0007cd, "Greek_NU" },
+  { 0x0007ce, "Greek_XI" },
+  { 0x0007cf, "Greek_OMICRON" },
+  { 0x0007d0, "Greek_PI" },
+  { 0x0007d1, "Greek_RHO" },
+  { 0x0007d2, "Greek_SIGMA" },
+  { 0x0007d4, "Greek_TAU" },
+  { 0x0007d5, "Greek_UPSILON" },
+  { 0x0007d6, "Greek_PHI" },
+  { 0x0007d7, "Greek_CHI" },
+  { 0x0007d8, "Greek_PSI" },
+  { 0x0007d9, "Greek_OMEGA" },
+  { 0x0007e1, "Greek_alpha" },
+  { 0x0007e2, "Greek_beta" },
+  { 0x0007e3, "Greek_gamma" },
+  { 0x0007e4, "Greek_delta" },
+  { 0x0007e5, "Greek_epsilon" },
+  { 0x0007e6, "Greek_zeta" },
+  { 0x0007e7, "Greek_eta" },
+  { 0x0007e8, "Greek_theta" },
+  { 0x0007e9, "Greek_iota" },
+  { 0x0007ea, "Greek_kappa" },
+  { 0x0007eb, "Greek_lambda" },
+  { 0x0007eb, "Greek_lamda" },
+  { 0x0007ec, "Greek_mu" },
+  { 0x0007ed, "Greek_nu" },
+  { 0x0007ee, "Greek_xi" },
+  { 0x0007ef, "Greek_omicron" },
+  { 0x0007f0, "Greek_pi" },
+  { 0x0007f1, "Greek_rho" },
+  { 0x0007f2, "Greek_sigma" },
+  { 0x0007f3, "Greek_finalsmallsigma" },
+  { 0x0007f4, "Greek_tau" },
+  { 0x0007f5, "Greek_upsilon" },
+  { 0x0007f6, "Greek_phi" },
+  { 0x0007f7, "Greek_chi" },
+  { 0x0007f8, "Greek_psi" },
+  { 0x0007f9, "Greek_omega" },
+  { 0x0008a1, "leftradical" },
+  { 0x0008a2, "topleftradical" },
+  { 0x0008a3, "horizconnector" },
+  { 0x0008a4, "topintegral" },
+  { 0x0008a5, "botintegral" },
+  { 0x0008a6, "vertconnector" },
+  { 0x0008a7, "topleftsqbracket" },
+  { 0x0008a8, "botleftsqbracket" },
+  { 0x0008a9, "toprightsqbracket" },
+  { 0x0008aa, "botrightsqbracket" },
+  { 0x0008ab, "topleftparens" },
+  { 0x0008ac, "botleftparens" },
+  { 0x0008ad, "toprightparens" },
+  { 0x0008ae, "botrightparens" },
+  { 0x0008af, "leftmiddlecurlybrace" },
+  { 0x0008b0, "rightmiddlecurlybrace" },
+  { 0x0008b1, "topleftsummation" },
+  { 0x0008b2, "botleftsummation" },
+  { 0x0008b3, "topvertsummationconnector" },
+  { 0x0008b4, "botvertsummationconnector" },
+  { 0x0008b5, "toprightsummation" },
+  { 0x0008b6, "botrightsummation" },
+  { 0x0008b7, "rightmiddlesummation" },
+  { 0x0008bc, "lessthanequal" },
+  { 0x0008bd, "notequal" },
+  { 0x0008be, "greaterthanequal" },
+  { 0x0008bf, "integral" },
+  { 0x0008c0, "therefore" },
+  { 0x0008c1, "variation" },
+  { 0x0008c2, "infinity" },
+  { 0x0008c5, "nabla" },
+  { 0x0008c8, "approximate" },
+  { 0x0008c9, "similarequal" },
+  { 0x0008cd, "ifonlyif" },
+  { 0x0008ce, "implies" },
+  { 0x0008cf, "identical" },
+  { 0x0008d6, "radical" },
+  { 0x0008da, "includedin" },
+  { 0x0008db, "includes" },
+  { 0x0008dc, "intersection" },
+  { 0x0008dd, "union" },
+  { 0x0008de, "logicaland" },
+  { 0x0008df, "logicalor" },
+  { 0x0008ef, "partialderivative" },
+  { 0x0008f6, "function" },
+  { 0x0008fb, "leftarrow" },
+  { 0x0008fc, "uparrow" },
+  { 0x0008fd, "rightarrow" },
+  { 0x0008fe, "downarrow" },
+  { 0x0009df, "blank" },
+  { 0x0009e0, "soliddiamond" },
+  { 0x0009e1, "checkerboard" },
+  { 0x0009e2, "ht" },
+  { 0x0009e3, "ff" },
+  { 0x0009e4, "cr" },
+  { 0x0009e5, "lf" },
+  { 0x0009e8, "nl" },
+  { 0x0009e9, "vt" },
+  { 0x0009ea, "lowrightcorner" },
+  { 0x0009eb, "uprightcorner" },
+  { 0x0009ec, "upleftcorner" },
+  { 0x0009ed, "lowleftcorner" },
+  { 0x0009ee, "crossinglines" },
+  { 0x0009ef, "horizlinescan1" },
+  { 0x0009f0, "horizlinescan3" },
+  { 0x0009f1, "horizlinescan5" },
+  { 0x0009f2, "horizlinescan7" },
+  { 0x0009f3, "horizlinescan9" },
+  { 0x0009f4, "leftt" },
+  { 0x0009f5, "rightt" },
+  { 0x0009f6, "bott" },
+  { 0x0009f7, "topt" },
+  { 0x0009f8, "vertbar" },
+  { 0x000aa1, "emspace" },
+  { 0x000aa2, "enspace" },
+  { 0x000aa3, "em3space" },
+  { 0x000aa4, "em4space" },
+  { 0x000aa5, "digitspace" },
+  { 0x000aa6, "punctspace" },
+  { 0x000aa7, "thinspace" },
+  { 0x000aa8, "hairspace" },
+  { 0x000aa9, "emdash" },
+  { 0x000aaa, "endash" },
+  { 0x000aac, "signifblank" },
+  { 0x000aae, "ellipsis" },
+  { 0x000aaf, "doubbaselinedot" },
+  { 0x000ab0, "onethird" },
+  { 0x000ab1, "twothirds" },
+  { 0x000ab2, "onefifth" },
+  { 0x000ab3, "twofifths" },
+  { 0x000ab4, "threefifths" },
+  { 0x000ab5, "fourfifths" },
+  { 0x000ab6, "onesixth" },
+  { 0x000ab7, "fivesixths" },
+  { 0x000ab8, "careof" },
+  { 0x000abb, "figdash" },
+  { 0x000abc, "leftanglebracket" },
+  { 0x000abd, "decimalpoint" },
+  { 0x000abe, "rightanglebracket" },
+  { 0x000abf, "marker" },
+  { 0x000ac3, "oneeighth" },
+  { 0x000ac4, "threeeighths" },
+  { 0x000ac5, "fiveeighths" },
+  { 0x000ac6, "seveneighths" },
+  { 0x000ac9, "trademark" },
+  { 0x000aca, "signaturemark" },
+  { 0x000acb, "trademarkincircle" },
+  { 0x000acc, "leftopentriangle" },
+  { 0x000acd, "rightopentriangle" },
+  { 0x000ace, "emopencircle" },
+  { 0x000acf, "emopenrectangle" },
+  { 0x000ad0, "leftsinglequotemark" },
+  { 0x000ad1, "rightsinglequotemark" },
+  { 0x000ad2, "leftdoublequotemark" },
+  { 0x000ad3, "rightdoublequotemark" },
+  { 0x000ad4, "prescription" },
+  { 0x000ad6, "minutes" },
+  { 0x000ad7, "seconds" },
+  { 0x000ad9, "latincross" },
+  { 0x000ada, "hexagram" },
+  { 0x000adb, "filledrectbullet" },
+  { 0x000adc, "filledlefttribullet" },
+  { 0x000add, "filledrighttribullet" },
+  { 0x000ade, "emfilledcircle" },
+  { 0x000adf, "emfilledrect" },
+  { 0x000ae0, "enopencircbullet" },
+  { 0x000ae1, "enopensquarebullet" },
+  { 0x000ae2, "openrectbullet" },
+  { 0x000ae3, "opentribulletup" },
+  { 0x000ae4, "opentribulletdown" },
+  { 0x000ae5, "openstar" },
+  { 0x000ae6, "enfilledcircbullet" },
+  { 0x000ae7, "enfilledsqbullet" },
+  { 0x000ae8, "filledtribulletup" },
+  { 0x000ae9, "filledtribulletdown" },
+  { 0x000aea, "leftpointer" },
+  { 0x000aeb, "rightpointer" },
+  { 0x000aec, "club" },
+  { 0x000aed, "diamond" },
+  { 0x000aee, "heart" },
+  { 0x000af0, "maltesecross" },
+  { 0x000af1, "dagger" },
+  { 0x000af2, "doubledagger" },
+  { 0x000af3, "checkmark" },
+  { 0x000af4, "ballotcross" },
+  { 0x000af5, "musicalsharp" },
+  { 0x000af6, "musicalflat" },
+  { 0x000af7, "malesymbol" },
+  { 0x000af8, "femalesymbol" },
+  { 0x000af9, "telephone" },
+  { 0x000afa, "telephonerecorder" },
+  { 0x000afb, "phonographcopyright" },
+  { 0x000afc, "caret" },
+  { 0x000afd, "singlelowquotemark" },
+  { 0x000afe, "doublelowquotemark" },
+  { 0x000aff, "cursor" },
+  { 0x000ba3, "leftcaret" },
+  { 0x000ba6, "rightcaret" },
+  { 0x000ba8, "downcaret" },
+  { 0x000ba9, "upcaret" },
+  { 0x000bc0, "overbar" },
+  { 0x000bc2, "downtack" },
+  { 0x000bc3, "upshoe" },
+  { 0x000bc4, "downstile" },
+  { 0x000bc6, "underbar" },
+  { 0x000bca, "jot" },
+  { 0x000bcc, "quad" },
+  { 0x000bce, "uptack" },
+  { 0x000bcf, "circle" },
+  { 0x000bd3, "upstile" },
+  { 0x000bd6, "downshoe" },
+  { 0x000bd8, "rightshoe" },
+  { 0x000bda, "leftshoe" },
+  { 0x000bdc, "lefttack" },
+  { 0x000bfc, "righttack" },
+  { 0x000cdf, "hebrew_doublelowline" },
+  { 0x000ce0, "hebrew_aleph" },
+  { 0x000ce1, "hebrew_bet" },
+  { 0x000ce1, "hebrew_beth" },
+  { 0x000ce2, "hebrew_gimel" },
+  { 0x000ce2, "hebrew_gimmel" },
+  { 0x000ce3, "hebrew_dalet" },
+  { 0x000ce3, "hebrew_daleth" },
+  { 0x000ce4, "hebrew_he" },
+  { 0x000ce5, "hebrew_waw" },
+  { 0x000ce6, "hebrew_zain" },
+  { 0x000ce6, "hebrew_zayin" },
+  { 0x000ce7, "hebrew_chet" },
+  { 0x000ce7, "hebrew_het" },
+  { 0x000ce8, "hebrew_tet" },
+  { 0x000ce8, "hebrew_teth" },
+  { 0x000ce9, "hebrew_yod" },
+  { 0x000cea, "hebrew_finalkaph" },
+  { 0x000ceb, "hebrew_kaph" },
+  { 0x000cec, "hebrew_lamed" },
+  { 0x000ced, "hebrew_finalmem" },
+  { 0x000cee, "hebrew_mem" },
+  { 0x000cef, "hebrew_finalnun" },
+  { 0x000cf0, "hebrew_nun" },
+  { 0x000cf1, "hebrew_samech" },
+  { 0x000cf1, "hebrew_samekh" },
+  { 0x000cf2, "hebrew_ayin" },
+  { 0x000cf3, "hebrew_finalpe" },
+  { 0x000cf4, "hebrew_pe" },
+  { 0x000cf5, "hebrew_finalzade" },
+  { 0x000cf5, "hebrew_finalzadi" },
+  { 0x000cf6, "hebrew_zade" },
+  { 0x000cf6, "hebrew_zadi" },
+  { 0x000cf7, "hebrew_kuf" },
+  { 0x000cf7, "hebrew_qoph" },
+  { 0x000cf8, "hebrew_resh" },
+  { 0x000cf9, "hebrew_shin" },
+  { 0x000cfa, "hebrew_taf" },
+  { 0x000cfa, "hebrew_taw" },
+  { 0x000da1, "Thai_kokai" },
+  { 0x000da2, "Thai_khokhai" },
+  { 0x000da3, "Thai_khokhuat" },
+  { 0x000da4, "Thai_khokhwai" },
+  { 0x000da5, "Thai_khokhon" },
+  { 0x000da6, "Thai_khorakhang" },
+  { 0x000da7, "Thai_ngongu" },
+  { 0x000da8, "Thai_chochan" },
+  { 0x000da9, "Thai_choching" },
+  { 0x000daa, "Thai_chochang" },
+  { 0x000dab, "Thai_soso" },
+  { 0x000dac, "Thai_chochoe" },
+  { 0x000dad, "Thai_yoying" },
+  { 0x000dae, "Thai_dochada" },
+  { 0x000daf, "Thai_topatak" },
+  { 0x000db0, "Thai_thothan" },
+  { 0x000db1, "Thai_thonangmontho" },
+  { 0x000db2, "Thai_thophuthao" },
+  { 0x000db3, "Thai_nonen" },
+  { 0x000db4, "Thai_dodek" },
+  { 0x000db5, "Thai_totao" },
+  { 0x000db6, "Thai_thothung" },
+  { 0x000db7, "Thai_thothahan" },
+  { 0x000db8, "Thai_thothong" },
+  { 0x000db9, "Thai_nonu" },
+  { 0x000dba, "Thai_bobaimai" },
+  { 0x000dbb, "Thai_popla" },
+  { 0x000dbc, "Thai_phophung" },
+  { 0x000dbd, "Thai_fofa" },
+  { 0x000dbe, "Thai_phophan" },
+  { 0x000dbf, "Thai_fofan" },
+  { 0x000dc0, "Thai_phosamphao" },
+  { 0x000dc1, "Thai_moma" },
+  { 0x000dc2, "Thai_yoyak" },
+  { 0x000dc3, "Thai_rorua" },
+  { 0x000dc4, "Thai_ru" },
+  { 0x000dc5, "Thai_loling" },
+  { 0x000dc6, "Thai_lu" },
+  { 0x000dc7, "Thai_wowaen" },
+  { 0x000dc8, "Thai_sosala" },
+  { 0x000dc9, "Thai_sorusi" },
+  { 0x000dca, "Thai_sosua" },
+  { 0x000dcb, "Thai_hohip" },
+  { 0x000dcc, "Thai_lochula" },
+  { 0x000dcd, "Thai_oang" },
+  { 0x000dce, "Thai_honokhuk" },
+  { 0x000dcf, "Thai_paiyannoi" },
+  { 0x000dd0, "Thai_saraa" },
+  { 0x000dd1, "Thai_maihanakat" },
+  { 0x000dd2, "Thai_saraaa" },
+  { 0x000dd3, "Thai_saraam" },
+  { 0x000dd4, "Thai_sarai" },
+  { 0x000dd5, "Thai_saraii" },
+  { 0x000dd6, "Thai_saraue" },
+  { 0x000dd7, "Thai_sarauee" },
+  { 0x000dd8, "Thai_sarau" },
+  { 0x000dd9, "Thai_sarauu" },
+  { 0x000dda, "Thai_phinthu" },
+  { 0x000dde, "Thai_maihanakat_maitho" },
+  { 0x000ddf, "Thai_baht" },
+  { 0x000de0, "Thai_sarae" },
+  { 0x000de1, "Thai_saraae" },
+  { 0x000de2, "Thai_sarao" },
+  { 0x000de3, "Thai_saraaimaimuan" },
+  { 0x000de4, "Thai_saraaimaimalai" },
+  { 0x000de5, "Thai_lakkhangyao" },
+  { 0x000de6, "Thai_maiyamok" },
+  { 0x000de7, "Thai_maitaikhu" },
+  { 0x000de8, "Thai_maiek" },
+  { 0x000de9, "Thai_maitho" },
+  { 0x000dea, "Thai_maitri" },
+  { 0x000deb, "Thai_maichattawa" },
+  { 0x000dec, "Thai_thanthakhat" },
+  { 0x000ded, "Thai_nikhahit" },
+  { 0x000df0, "Thai_leksun" },
+  { 0x000df1, "Thai_leknung" },
+  { 0x000df2, "Thai_leksong" },
+  { 0x000df3, "Thai_leksam" },
+  { 0x000df4, "Thai_leksi" },
+  { 0x000df5, "Thai_lekha" },
+  { 0x000df6, "Thai_lekhok" },
+  { 0x000df7, "Thai_lekchet" },
+  { 0x000df8, "Thai_lekpaet" },
+  { 0x000df9, "Thai_lekkao" },
+  { 0x000ea1, "Hangul_Kiyeog" },
+  { 0x000ea2, "Hangul_SsangKiyeog" },
+  { 0x000ea3, "Hangul_KiyeogSios" },
+  { 0x000ea4, "Hangul_Nieun" },
+  { 0x000ea5, "Hangul_NieunJieuj" },
+  { 0x000ea6, "Hangul_NieunHieuh" },
+  { 0x000ea7, "Hangul_Dikeud" },
+  { 0x000ea8, "Hangul_SsangDikeud" },
+  { 0x000ea9, "Hangul_Rieul" },
+  { 0x000eaa, "Hangul_RieulKiyeog" },
+  { 0x000eab, "Hangul_RieulMieum" },
+  { 0x000eac, "Hangul_RieulPieub" },
+  { 0x000ead, "Hangul_RieulSios" },
+  { 0x000eae, "Hangul_RieulTieut" },
+  { 0x000eaf, "Hangul_RieulPhieuf" },
+  { 0x000eb0, "Hangul_RieulHieuh" },
+  { 0x000eb1, "Hangul_Mieum" },
+  { 0x000eb2, "Hangul_Pieub" },
+  { 0x000eb3, "Hangul_SsangPieub" },
+  { 0x000eb4, "Hangul_PieubSios" },
+  { 0x000eb5, "Hangul_Sios" },
+  { 0x000eb6, "Hangul_SsangSios" },
+  { 0x000eb7, "Hangul_Ieung" },
+  { 0x000eb8, "Hangul_Jieuj" },
+  { 0x000eb9, "Hangul_SsangJieuj" },
+  { 0x000eba, "Hangul_Cieuc" },
+  { 0x000ebb, "Hangul_Khieuq" },
+  { 0x000ebc, "Hangul_Tieut" },
+  { 0x000ebd, "Hangul_Phieuf" },
+  { 0x000ebe, "Hangul_Hieuh" },
+  { 0x000ebf, "Hangul_A" },
+  { 0x000ec0, "Hangul_AE" },
+  { 0x000ec1, "Hangul_YA" },
+  { 0x000ec2, "Hangul_YAE" },
+  { 0x000ec3, "Hangul_EO" },
+  { 0x000ec4, "Hangul_E" },
+  { 0x000ec5, "Hangul_YEO" },
+  { 0x000ec6, "Hangul_YE" },
+  { 0x000ec7, "Hangul_O" },
+  { 0x000ec8, "Hangul_WA" },
+  { 0x000ec9, "Hangul_WAE" },
+  { 0x000eca, "Hangul_OE" },
+  { 0x000ecb, "Hangul_YO" },
+  { 0x000ecc, "Hangul_U" },
+  { 0x000ecd, "Hangul_WEO" },
+  { 0x000ece, "Hangul_WE" },
+  { 0x000ecf, "Hangul_WI" },
+  { 0x000ed0, "Hangul_YU" },
+  { 0x000ed1, "Hangul_EU" },
+  { 0x000ed2, "Hangul_YI" },
+  { 0x000ed3, "Hangul_I" },
+  { 0x000ed4, "Hangul_J_Kiyeog" },
+  { 0x000ed5, "Hangul_J_SsangKiyeog" },
+  { 0x000ed6, "Hangul_J_KiyeogSios" },
+  { 0x000ed7, "Hangul_J_Nieun" },
+  { 0x000ed8, "Hangul_J_NieunJieuj" },
+  { 0x000ed9, "Hangul_J_NieunHieuh" },
+  { 0x000eda, "Hangul_J_Dikeud" },
+  { 0x000edb, "Hangul_J_Rieul" },
+  { 0x000edc, "Hangul_J_RieulKiyeog" },
+  { 0x000edd, "Hangul_J_RieulMieum" },
+  { 0x000ede, "Hangul_J_RieulPieub" },
+  { 0x000edf, "Hangul_J_RieulSios" },
+  { 0x000ee0, "Hangul_J_RieulTieut" },
+  { 0x000ee1, "Hangul_J_RieulPhieuf" },
+  { 0x000ee2, "Hangul_J_RieulHieuh" },
+  { 0x000ee3, "Hangul_J_Mieum" },
+  { 0x000ee4, "Hangul_J_Pieub" },
+  { 0x000ee5, "Hangul_J_PieubSios" },
+  { 0x000ee6, "Hangul_J_Sios" },
+  { 0x000ee7, "Hangul_J_SsangSios" },
+  { 0x000ee8, "Hangul_J_Ieung" },
+  { 0x000ee9, "Hangul_J_Jieuj" },
+  { 0x000eea, "Hangul_J_Cieuc" },
+  { 0x000eeb, "Hangul_J_Khieuq" },
+  { 0x000eec, "Hangul_J_Tieut" },
+  { 0x000eed, "Hangul_J_Phieuf" },
+  { 0x000eee, "Hangul_J_Hieuh" },
+  { 0x000eef, "Hangul_RieulYeorinHieuh" },
+  { 0x000ef0, "Hangul_SunkyeongeumMieum" },
+  { 0x000ef1, "Hangul_SunkyeongeumPieub" },
+  { 0x000ef2, "Hangul_PanSios" },
+  { 0x000ef3, "Hangul_KkogjiDalrinIeung" },
+  { 0x000ef4, "Hangul_SunkyeongeumPhieuf" },
+  { 0x000ef5, "Hangul_YeorinHieuh" },
+  { 0x000ef6, "Hangul_AraeA" },
+  { 0x000ef7, "Hangul_AraeAE" },
+  { 0x000ef8, "Hangul_J_PanSios" },
+  { 0x000ef9, "Hangul_J_KkogjiDalrinIeung" },
+  { 0x000efa, "Hangul_J_YeorinHieuh" },
+  { 0x000eff, "Korean_Won" },
+  { 0x00FD01, "3270_Duplicate" },
+  { 0x00FD02, "3270_FieldMark" },
+  { 0x00FD03, "3270_Right2" },
+  { 0x00FD04, "3270_Left2" },
+  { 0x00FD05, "3270_BackTab" },
+  { 0x00FD06, "3270_EraseEOF" },
+  { 0x00FD07, "3270_EraseInput" },
+  { 0x00FD08, "3270_Reset" },
+  { 0x00FD09, "3270_Quit" },
+  { 0x00FD0A, "3270_PA1" },
+  { 0x00FD0B, "3270_PA2" },
+  { 0x00FD0C, "3270_PA3" },
+  { 0x00FD0D, "3270_Test" },
+  { 0x00FD0E, "3270_Attn" },
+  { 0x00FD0F, "3270_CursorBlink" },
+  { 0x00FD10, "3270_AltCursor" },
+  { 0x00FD11, "3270_KeyClick" },
+  { 0x00FD12, "3270_Jump" },
+  { 0x00FD13, "3270_Ident" },
+  { 0x00FD14, "3270_Rule" },
+  { 0x00FD15, "3270_Copy" },
+  { 0x00FD16, "3270_Play" },
+  { 0x00FD17, "3270_Setup" },
+  { 0x00FD18, "3270_Record" },
+  { 0x00FD19, "3270_ChangeScreen" },
+  { 0x00FD1A, "3270_DeleteWord" },
+  { 0x00FD1B, "3270_ExSelect" },
+  { 0x00FD1C, "3270_CursorSelect" },
+  { 0x00FD1D, "3270_PrintScreen" },
+  { 0x00FD1E, "3270_Enter" },
+  { 0x00FE01, "ISO_Lock" },
+  { 0x00FE02, "ISO_Level2_Latch" },
+  { 0x00FE03, "ISO_Level3_Shift" },
+  { 0x00FE04, "ISO_Level3_Latch" },
+  { 0x00FE05, "ISO_Level3_Lock" },
+  { 0x00FE06, "ISO_Group_Latch" },
+  { 0x00FE07, "ISO_Group_Lock" },
+  { 0x00FE08, "ISO_Next_Group" },
+  { 0x00FE09, "ISO_Next_Group_Lock" },
+  { 0x00FE0A, "ISO_Prev_Group" },
+  { 0x00FE0B, "ISO_Prev_Group_Lock" },
+  { 0x00FE0C, "ISO_First_Group" },
+  { 0x00FE0D, "ISO_First_Group_Lock" },
+  { 0x00FE0E, "ISO_Last_Group" },
+  { 0x00FE0F, "ISO_Last_Group_Lock" },
+  { 0x00FE20, "ISO_Left_Tab" },
+  { 0x00FE21, "ISO_Move_Line_Up" },
+  { 0x00FE22, "ISO_Move_Line_Down" },
+  { 0x00FE23, "ISO_Partial_Line_Up" },
+  { 0x00FE24, "ISO_Partial_Line_Down" },
+  { 0x00FE25, "ISO_Partial_Space_Left" },
+  { 0x00FE26, "ISO_Partial_Space_Right" },
+  { 0x00FE27, "ISO_Set_Margin_Left" },
+  { 0x00FE28, "ISO_Set_Margin_Right" },
+  { 0x00FE29, "ISO_Release_Margin_Left" },
+  { 0x00FE2A, "ISO_Release_Margin_Right" },
+  { 0x00FE2B, "ISO_Release_Both_Margins" },
+  { 0x00FE2C, "ISO_Fast_Cursor_Left" },
+  { 0x00FE2D, "ISO_Fast_Cursor_Right" },
+  { 0x00FE2E, "ISO_Fast_Cursor_Up" },
+  { 0x00FE2F, "ISO_Fast_Cursor_Down" },
+  { 0x00FE30, "ISO_Continuous_Underline" },
+  { 0x00FE31, "ISO_Discontinuous_Underline" },
+  { 0x00FE32, "ISO_Emphasize" },
+  { 0x00FE33, "ISO_Center_Object" },
+  { 0x00FE34, "ISO_Enter" },
+  { 0x00FE50, "dead_grave" },
+  { 0x00FE51, "dead_acute" },
+  { 0x00FE52, "dead_circumflex" },
+  { 0x00FE53, "dead_tilde" },
+  { 0x00FE54, "dead_macron" },
+  { 0x00FE55, "dead_breve" },
+  { 0x00FE56, "dead_abovedot" },
+  { 0x00FE57, "dead_diaeresis" },
+  { 0x00FE58, "dead_abovering" },
+  { 0x00FE59, "dead_doubleacute" },
+  { 0x00FE5A, "dead_caron" },
+  { 0x00FE5B, "dead_cedilla" },
+  { 0x00FE5C, "dead_ogonek" },
+  { 0x00FE5D, "dead_iota" },
+  { 0x00FE5E, "dead_voiced_sound" },
+  { 0x00FE5F, "dead_semivoiced_sound" },
+  { 0x00FE60, "dead_belowdot" },
+  { 0x00FE70, "AccessX_Enable" },
+  { 0x00FE71, "AccessX_Feedback_Enable" },
+  { 0x00FE72, "RepeatKeys_Enable" },
+  { 0x00FE73, "SlowKeys_Enable" },
+  { 0x00FE74, "BounceKeys_Enable" },
+  { 0x00FE75, "StickyKeys_Enable" },
+  { 0x00FE76, "MouseKeys_Enable" },
+  { 0x00FE77, "MouseKeys_Accel_Enable" },
+  { 0x00FE78, "Overlay1_Enable" },
+  { 0x00FE79, "Overlay2_Enable" },
+  { 0x00FE7A, "AudibleBell_Enable" },
+  { 0x00FED0, "First_Virtual_Screen" },
+  { 0x00FED1, "Prev_Virtual_Screen" },
+  { 0x00FED2, "Next_Virtual_Screen" },
+  { 0x00FED4, "Last_Virtual_Screen" },
+  { 0x00FED5, "Terminate_Server" },
+  { 0x00FEE0, "Pointer_Left" },
+  { 0x00FEE1, "Pointer_Right" },
+  { 0x00FEE2, "Pointer_Up" },
+  { 0x00FEE3, "Pointer_Down" },
+  { 0x00FEE4, "Pointer_UpLeft" },
+  { 0x00FEE5, "Pointer_UpRight" },
+  { 0x00FEE6, "Pointer_DownLeft" },
+  { 0x00FEE7, "Pointer_DownRight" },
+  { 0x00FEE8, "Pointer_Button_Dflt" },
+  { 0x00FEE9, "Pointer_Button1" },
+  { 0x00FEEA, "Pointer_Button2" },
+  { 0x00FEEB, "Pointer_Button3" },
+  { 0x00FEEC, "Pointer_Button4" },
+  { 0x00FEED, "Pointer_Button5" },
+  { 0x00FEEE, "Pointer_DblClick_Dflt" },
+  { 0x00FEEF, "Pointer_DblClick1" },
+  { 0x00FEF0, "Pointer_DblClick2" },
+  { 0x00FEF1, "Pointer_DblClick3" },
+  { 0x00FEF2, "Pointer_DblClick4" },
+  { 0x00FEF3, "Pointer_DblClick5" },
+  { 0x00FEF4, "Pointer_Drag_Dflt" },
+  { 0x00FEF5, "Pointer_Drag1" },
+  { 0x00FEF6, "Pointer_Drag2" },
+  { 0x00FEF7, "Pointer_Drag3" },
+  { 0x00FEF8, "Pointer_Drag4" },
+  { 0x00FEF9, "Pointer_EnableKeys" },
+  { 0x00FEFA, "Pointer_Accelerate" },
+  { 0x00FEFB, "Pointer_DfltBtnNext" },
+  { 0x00FEFC, "Pointer_DfltBtnPrev" },
+  { 0x00FEFD, "Pointer_Drag5" },
+  { 0x00FF08, "BackSpace" },
+  { 0x00FF09, "Tab" },
+  { 0x00FF0A, "Linefeed" },
+  { 0x00FF0B, "Clear" },
+  { 0x00FF0D, "Return" },
+  { 0x00FF13, "Pause" },
+  { 0x00FF14, "Scroll_Lock" },
+  { 0x00FF15, "Sys_Req" },
+  { 0x00FF1B, "Escape" },
+  { 0x00FF20, "Multi_key" },
+  { 0x00FF21, "Kanji" },
+  { 0x00FF22, "Muhenkan" },
+  { 0x00FF23, "Henkan" },
+  { 0x00FF23, "Henkan_Mode" },
+  { 0x00FF24, "Romaji" },
+  { 0x00FF25, "Hiragana" },
+  { 0x00FF26, "Katakana" },
+  { 0x00FF27, "Hiragana_Katakana" },
+  { 0x00FF28, "Zenkaku" },
+  { 0x00FF29, "Hankaku" },
+  { 0x00FF2A, "Zenkaku_Hankaku" },
+  { 0x00FF2B, "Touroku" },
+  { 0x00FF2C, "Massyo" },
+  { 0x00FF2D, "Kana_Lock" },
+  { 0x00FF2E, "Kana_Shift" },
+  { 0x00FF2F, "Eisu_Shift" },
+  { 0x00FF30, "Eisu_toggle" },
+  { 0x00FF3C, "SingleCandidate" },
+  { 0x00FF3D, "MultipleCandidate" },
+  { 0x00FF3D, "Zen_Koho" },
+  { 0x00FF3E, "Mae_Koho" },
+  { 0x00FF3E, "PreviousCandidate" },
+  { 0x00FF50, "Home" },
+  { 0x00FF51, "Left" },
+  { 0x00FF52, "Up" },
+  { 0x00FF53, "Right" },
+  { 0x00FF54, "Down" },
+  { 0x00FF55, "Page_Up" },
+  { 0x00FF55, "Prior" },
+  { 0x00FF56, "Next" },
+  { 0x00FF56, "Page_Down" },
+  { 0x00FF57, "End" },
+  { 0x00FF58, "Begin" },
+  { 0x00FF60, "Select" },
+  { 0x00FF61, "Print" },
+  { 0x00FF62, "Execute" },
+  { 0x00FF63, "Insert" },
+  { 0x00FF65, "Undo" },
+  { 0x00FF66, "Redo" },
+  { 0x00FF67, "Menu" },
+  { 0x00FF68, "Find" },
+  { 0x00FF69, "Cancel" },
+  { 0x00FF6A, "Help" },
+  { 0x00FF6B, "Break" },
+  { 0x00FF7E, "Arabic_switch" },
+  { 0x00FF7E, "Greek_switch" },
+  { 0x00FF7E, "Hangul_switch" },
+  { 0x00FF7E, "Hebrew_switch" },
+  { 0x00FF7E, "ISO_Group_Shift" },
+  { 0x00FF7E, "Mode_switch" },
+  { 0x00FF7E, "kana_switch" },
+  { 0x00FF7E, "script_switch" },
+  { 0x00FF7F, "Num_Lock" },
+  { 0x00FF80, "KP_Space" },
+  { 0x00FF89, "KP_Tab" },
+  { 0x00FF8D, "KP_Enter" },
+  { 0x00FF91, "KP_F1" },
+  { 0x00FF92, "KP_F2" },
+  { 0x00FF93, "KP_F3" },
+  { 0x00FF94, "KP_F4" },
+  { 0x00FF95, "KP_Home" },
+  { 0x00FF96, "KP_Left" },
+  { 0x00FF97, "KP_Up" },
+  { 0x00FF98, "KP_Right" },
+  { 0x00FF99, "KP_Down" },
+  { 0x00FF9A, "KP_Page_Up" },
+  { 0x00FF9A, "KP_Prior" },
+  { 0x00FF9B, "KP_Next" },
+  { 0x00FF9B, "KP_Page_Down" },
+  { 0x00FF9C, "KP_End" },
+  { 0x00FF9D, "KP_Begin" },
+  { 0x00FF9E, "KP_Insert" },
+  { 0x00FF9F, "KP_Delete" },
+  { 0x00FFAA, "KP_Multiply" },
+  { 0x00FFAB, "KP_Add" },
+  { 0x00FFAC, "KP_Separator" },
+  { 0x00FFAD, "KP_Subtract" },
+  { 0x00FFAE, "KP_Decimal" },
+  { 0x00FFAF, "KP_Divide" },
+  { 0x00FFB0, "KP_0" },
+  { 0x00FFB1, "KP_1" },
+  { 0x00FFB2, "KP_2" },
+  { 0x00FFB3, "KP_3" },
+  { 0x00FFB4, "KP_4" },
+  { 0x00FFB5, "KP_5" },
+  { 0x00FFB6, "KP_6" },
+  { 0x00FFB7, "KP_7" },
+  { 0x00FFB8, "KP_8" },
+  { 0x00FFB9, "KP_9" },
+  { 0x00FFBD, "KP_Equal" },
+  { 0x00FFBE, "F1" },
+  { 0x00FFBF, "F2" },
+  { 0x00FFC0, "F3" },
+  { 0x00FFC1, "F4" },
+  { 0x00FFC2, "F5" },
+  { 0x00FFC3, "F6" },
+  { 0x00FFC4, "F7" },
+  { 0x00FFC5, "F8" },
+  { 0x00FFC6, "F9" },
+  { 0x00FFC7, "F10" },
+  { 0x00FFC8, "F11" },
+  { 0x00FFC8, "L1" },
+  { 0x00FFC9, "F12" },
+  { 0x00FFC9, "L2" },
+  { 0x00FFCA, "F13" },
+  { 0x00FFCA, "L3" },
+  { 0x00FFCB, "F14" },
+  { 0x00FFCB, "L4" },
+  { 0x00FFCC, "F15" },
+  { 0x00FFCC, "L5" },
+  { 0x00FFCD, "F16" },
+  { 0x00FFCD, "L6" },
+  { 0x00FFCE, "F17" },
+  { 0x00FFCE, "L7" },
+  { 0x00FFCF, "F18" },
+  { 0x00FFCF, "L8" },
+  { 0x00FFD0, "F19" },
+  { 0x00FFD0, "L9" },
+  { 0x00FFD1, "F20" },
+  { 0x00FFD1, "L10" },
+  { 0x00FFD2, "F21" },
+  { 0x00FFD2, "R1" },
+  { 0x00FFD3, "F22" },
+  { 0x00FFD3, "R2" },
+  { 0x00FFD4, "F23" },
+  { 0x00FFD4, "R3" },
+  { 0x00FFD5, "F24" },
+  { 0x00FFD5, "R4" },
+  { 0x00FFD6, "F25" },
+  { 0x00FFD6, "R5" },
+  { 0x00FFD7, "F26" },
+  { 0x00FFD7, "R6" },
+  { 0x00FFD8, "F27" },
+  { 0x00FFD8, "R7" },
+  { 0x00FFD9, "F28" },
+  { 0x00FFD9, "R8" },
+  { 0x00FFDA, "F29" },
+  { 0x00FFDA, "R9" },
+  { 0x00FFDB, "F30" },
+  { 0x00FFDB, "R10" },
+  { 0x00FFDC, "F31" },
+  { 0x00FFDC, "R11" },
+  { 0x00FFDD, "F32" },
+  { 0x00FFDD, "R12" },
+  { 0x00FFDE, "F33" },
+  { 0x00FFDE, "R13" },
+  { 0x00FFDF, "F34" },
+  { 0x00FFDF, "R14" },
+  { 0x00FFE0, "F35" },
+  { 0x00FFE0, "R15" },
+  { 0x00FFE1, "Shift_L" },
+  { 0x00FFE2, "Shift_R" },
+  { 0x00FFE3, "Control_L" },
+  { 0x00FFE4, "Control_R" },
+  { 0x00FFE5, "Caps_Lock" },
+  { 0x00FFE6, "Shift_Lock" },
+  { 0x00FFE7, "Meta_L" },
+  { 0x00FFE8, "Meta_R" },
+  { 0x00FFE9, "Alt_L" },
+  { 0x00FFEA, "Alt_R" },
+  { 0x00FFEB, "Super_L" },
+  { 0x00FFEC, "Super_R" },
+  { 0x00FFED, "Hyper_L" },
+  { 0x00FFEE, "Hyper_R" },
+  { 0x00FFFF, "Delete" },
+  { 0x00ff31, "Hangul" },
+  { 0x00ff32, "Hangul_Start" },
+  { 0x00ff33, "Hangul_End" },
+  { 0x00ff34, "Hangul_Hanja" },
+  { 0x00ff35, "Hangul_Jamo" },
+  { 0x00ff36, "Hangul_Romaja" },
+  { 0x00ff37, "Hangul_Codeinput" },
+  { 0x00ff38, "Hangul_Jeonja" },
+  { 0x00ff39, "Hangul_Banja" },
+  { 0x00ff3a, "Hangul_PreHanja" },
+  { 0x00ff3b, "Hangul_PostHanja" },
+  { 0x00ff3c, "Hangul_SingleCandidate" },
+  { 0x00ff3d, "Hangul_MultipleCandidate" },
+  { 0x00ff3e, "Hangul_PreviousCandidate" },
+  { 0x00ff3f, "Hangul_Special" },
+  { 0xFFFFFF, "VoidSymbol" },
+};
+
+#define GDK_NUM_KEYS (sizeof (gdk_keys_by_keyval) / sizeof (gdk_keys_by_keyval[0]))
+
+static struct gdk_key *gdk_keys_by_name = NULL;
+
+static int
+gdk_keys_keyval_compare (const void *pkey, const void *pbase)
+{
+  return (*(int *) pkey) - ((struct gdk_key *) pbase)->keyval;
+}
+
+const gchar*
+gdk_keyval_name (guint       keyval)
+{
+  struct gdk_key *found =
+    bsearch (&keyval, gdk_keys_by_keyval,
+            GDK_NUM_KEYS, sizeof (struct gdk_key),
+            gdk_keys_keyval_compare);
+  if (found != NULL)
+    return found->name;
+  else
+    return NULL;
+}
+
+static int 
+gdk_key_compare_by_name (const void *a, const void *b)
+{
+  return strcmp (((const struct gdk_key *) a)->name, ((const struct gdk_key *) b)->name);
+}
+
+static int
+gdk_keys_name_compare (const void *pkey, const void *pbase)
+{
+  return strcmp ((const char *) pkey, ((const struct gdk_key *) pbase)->name);
+}
+
+guint
+gdk_keyval_from_name (const gchar *keyval_name)
+{
+  struct gdk_key *found;
+
+  g_return_val_if_fail (keyval_name != NULL, 0);
+  
+  if (gdk_keys_by_name == NULL)
+    {
+      gdk_keys_by_name = g_new (struct gdk_key, GDK_NUM_KEYS);
+
+      memcpy (gdk_keys_by_name, gdk_keys_by_keyval,
+             GDK_NUM_KEYS * sizeof (struct gdk_key));
+
+      qsort (gdk_keys_by_name, GDK_NUM_KEYS, sizeof (struct gdk_key),
+            gdk_key_compare_by_name);
+    }
+
+  found = bsearch (keyval_name, gdk_keys_by_name,
+                  GDK_NUM_KEYS, sizeof (struct gdk_key),
+                  gdk_keys_name_compare);
+  if (found != NULL)
+    return found->keyval;
+  else
+    return GDK_VoidSymbol;
+}
+
+guint
+gdk_keyval_to_upper (guint       keyval)
+{
+  if (keyval)
+    {
+      KeySym lower_val = 0;
+      KeySym upper_val = 0;
+      
+      XConvertCase (keyval, &lower_val, &upper_val);
+      return upper_val;
+    }
+  return 0;
+}
+
+guint
+gdk_keyval_to_lower (guint       keyval)
+{
+  if (keyval)
+    {
+      KeySym lower_val = 0;
+      KeySym upper_val = 0;
+      
+      XConvertCase (keyval, &lower_val, &upper_val);
+      return lower_val;
+    }
+  return 0;
+}
+
+gboolean
+gdk_keyval_is_upper (guint       keyval)
+{
+  if (keyval)
+    {
+      KeySym lower_val = 0;
+      KeySym upper_val = 0;
+      
+      XConvertCase (keyval, &lower_val, &upper_val);
+      return upper_val == keyval;
+    }
+  return TRUE;
+}
+
+gboolean
+gdk_keyval_is_lower (guint        keyval)
+{
+  if (keyval)
+    {
+      KeySym lower_val = 0;
+      KeySym upper_val = 0;
+      
+      XConvertCase (keyval, &lower_val, &upper_val);
+      return lower_val == keyval;
+    }
+  return TRUE;
+}
+
+
+void
+gdk_threads_enter ()
+{
+  GDK_THREADS_ENTER ();
+}
+
+void
+gdk_threads_leave ()
+{
+  GDK_THREADS_LEAVE ();
+}
diff --git a/gdk/win32/gdkpixmap-win32.c b/gdk/win32/gdkpixmap-win32.c
new file mode 100644 (file)
index 0000000..e8a6c02
--- /dev/null
@@ -0,0 +1,1059 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-1999 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gdk.h"
+#include "gdkprivate.h"
+
+typedef struct
+{
+  gchar *color_string;
+  GdkColor color;
+  gint transparent;
+} _GdkPixmapColor;
+
+typedef struct
+{
+  guint ncolors;
+  GdkColormap *colormap;
+  gulong pixels[1];
+} _GdkPixmapInfo;
+
+GdkPixmap*
+gdk_pixmap_new (GdkWindow *window,
+               gint       width,
+               gint       height,
+               gint       depth)
+{
+  GdkPixmap *pixmap;
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *window_private;
+  struct {
+    BITMAPINFOHEADER bmiHeader;
+    union {
+      WORD bmiIndices[256];
+      DWORD bmiMasks[3];
+      RGBQUAD bmiColors[256];
+    } u;
+  } bmi;
+  UINT iUsage;
+  HDC hdc;
+  GdkVisual *visual;
+  guchar *bits;
+  gint i;
+
+  g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
+  g_return_val_if_fail ((width != 0) && (height != 0), NULL);
+
+  if (!window)
+    window = (GdkWindow*) &gdk_root_parent;
+
+  window_private = (GdkWindowPrivate*) window;
+  if (window_private->destroyed)
+    return NULL;
+
+  if (depth == -1)
+    depth = gdk_window_get_visual (window)->depth;
+
+  GDK_NOTE (MISC, g_print ("gdk_pixmap_new: %dx%dx%d\n", width, height, depth));
+
+  private = g_new0 (GdkWindowPrivate, 1);
+  pixmap = (GdkPixmap*) private;
+
+  private->window_type = GDK_WINDOW_PIXMAP;
+
+  visual = gdk_window_get_visual (window);
+
+#if 0
+  if (depth == 1)
+    {
+      if ((private->xwindow =
+          CreateBitmap (width, height, 1, 1, NULL)) == NULL)
+       {
+         g_warning ("gdk_pixmap_new: CreateBitmap failed");
+         g_free (private);
+         return NULL;
+       }
+
+      private->colormap = NULL;
+    }
+  else
+    {
+      if (depth != visual->depth)
+       g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d",
+                  depth, visual->depth);
+
+      if ((hdc = GetDC (window_private->xwindow)) == NULL)
+       {
+         g_warning ("gdk_pixmap_new: GetDC failed");
+         g_free (private);
+         return NULL;
+       }
+
+      if ((private->xwindow =
+          CreateCompatibleBitmap (hdc, width, height)) == NULL)
+       {
+         g_warning ("gdk_pixmap_new: %dx%d CreateCompatibleBitmap failed",
+                    width, height);
+         ReleaseDC (window_private->xwindow, hdc);
+         g_free (private);
+         return NULL;
+       }
+
+      ReleaseDC (window_private->xwindow, hdc);
+
+      private->colormap = window_private->colormap;
+      if (private->colormap == NULL)
+       private->colormap = gdk_colormap_get_system ();
+    }
+#else
+
+  if ((hdc = GetDC (window_private->xwindow)) == NULL)
+    {
+      g_warning ("gdk_pixmap_new: GetDC failed");
+      g_free (private);
+      return NULL;
+    }
+
+  bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+  bmi.bmiHeader.biWidth = width;
+  bmi.bmiHeader.biHeight = -height;
+  bmi.bmiHeader.biPlanes = 1;
+  if (depth == 15)
+    bmi.bmiHeader.biBitCount = 16;
+  else
+    bmi.bmiHeader.biBitCount = depth;
+#if 1
+  if (depth == 16)
+    bmi.bmiHeader.biCompression = BI_BITFIELDS;
+  else
+#endif
+    bmi.bmiHeader.biCompression = BI_RGB;
+  bmi.bmiHeader.biSizeImage = 0;
+  bmi.bmiHeader.biXPelsPerMeter =
+    bmi.bmiHeader.biYPelsPerMeter = 0;
+  bmi.bmiHeader.biClrUsed = 0;
+  bmi.bmiHeader.biClrImportant = 0;
+
+  iUsage = DIB_RGB_COLORS;
+  if (depth == 1)
+    {
+      bmi.u.bmiColors[0].rgbBlue =
+       bmi.u.bmiColors[0].rgbGreen =
+       bmi.u.bmiColors[0].rgbRed = 0x00;
+      bmi.u.bmiColors[0].rgbReserved = 0x00;
+
+      bmi.u.bmiColors[1].rgbBlue =
+       bmi.u.bmiColors[1].rgbGreen =
+      bmi.u.bmiColors[1].rgbRed = 0xFF;
+      bmi.u.bmiColors[1].rgbReserved = 0x00;
+      private->colormap = NULL;
+    }
+  else
+    {
+      private->colormap = window_private->colormap;
+      if (private->colormap == NULL)
+       private->colormap = gdk_colormap_get_system ();
+
+      if (depth == 8)
+       {
+         iUsage = DIB_PAL_COLORS;
+         for (i = 0; i < 256; i++)
+           bmi.u.bmiIndices[i] = i;
+       }
+      else
+       {
+         if (depth != visual->depth)
+           g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d",
+                      depth, visual->depth);
+#if 1
+         if (depth == 16)
+           {
+             bmi.u.bmiMasks[0] = visual->red_mask;
+             bmi.u.bmiMasks[1] = visual->green_mask;
+             bmi.u.bmiMasks[2] = visual->blue_mask;
+           }
+#endif
+       }
+    }
+  if ((private->xwindow =
+       CreateDIBSection (hdc, (BITMAPINFO *) &bmi,
+                        iUsage, &bits, NULL, 0)) == NULL)
+    {
+      g_warning ("gdk_pixmap_new: CreateDIBSection failed: %d", GetLastError ());
+      ReleaseDC (window_private->xwindow, hdc);
+      g_free (private);
+      return NULL;
+    }
+  ReleaseDC (window_private->xwindow, hdc);
+
+#endif
+
+  GDK_NOTE (MISC, g_print ("... = %#x\n", private->xwindow));
+
+  private->parent = NULL;
+  private->x = 0;
+  private->y = 0;
+  private->width = width;
+  private->height = height;
+  private->resize_count = 0;
+  private->ref_count = 1;
+  private->destroyed = 0;
+
+  gdk_xid_table_insert (&private->xwindow, pixmap);
+
+  return pixmap;
+}
+
+GdkPixmap *
+gdk_pixmap_create_on_shared_image (GdkImage **image_return,
+                                  GdkWindow *window,
+                                  GdkVisual *visual,
+                                  gint       width,
+                                  gint       height,
+                                  gint       depth)
+{
+  GdkPixmap *pixmap;
+  GdkImagePrivate *image_private;
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *window_private;
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  window_private = (GdkWindowPrivate *) window;
+
+  if (depth == 1)
+    *image_return = gdk_image_bitmap_new (GDK_IMAGE_SHARED_PIXMAP, visual, width, height);
+  else
+    {
+      g_return_val_if_fail (depth == visual->depth, NULL);
+      *image_return = gdk_image_new (GDK_IMAGE_SHARED_PIXMAP, visual, width, height);
+    }
+
+  g_return_val_if_fail (*image_return != NULL, NULL);
+
+  image_private = (GdkImagePrivate *) *image_return;
+
+  private = g_new0 (GdkWindowPrivate, 1);
+  pixmap = (GdkPixmap*) private;
+
+  private->xwindow = image_private->ximage;
+  private->window_type = GDK_WINDOW_PIXMAP;
+  private->colormap = window_private->colormap;
+  private->parent = NULL;
+  private->x = 0;
+  private->y = 0;
+  private->width = width;
+  private->height = height;
+  private->resize_count = 0;
+  private->ref_count = 1;
+  private->destroyed = 0;
+
+  gdk_xid_table_insert (&private->xwindow, pixmap);
+
+  GDK_NOTE (MISC,
+           g_print ("gdk_pixmap_create_on_shared_image: %dx%dx%d = %#x\n",
+                    width, height, depth, private->xwindow));
+
+  return pixmap;
+}
+
+static unsigned char mirror[256] = {
+  0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+  0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+  0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+  0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+  0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+  0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+  0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+  0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+  0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+  0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+  0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+  0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+  0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+  0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+  0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+  0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+  0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+  0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+  0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+  0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+  0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+  0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+  0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+  0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+  0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+  0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+  0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+  0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+  0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+  0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+  0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+  0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+GdkPixmap *
+gdk_bitmap_create_from_data (GdkWindow   *window,
+                            const gchar *data,
+                            gint         width,
+                            gint         height)
+{
+  GdkPixmap *pixmap;
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *window_private;
+  gint i, j, bpl, aligned_bpl;
+  guchar *bits;
+
+  g_return_val_if_fail (data != NULL, NULL);
+  g_return_val_if_fail ((width != 0) && (height != 0), NULL);
+
+  if (!window)
+    window = (GdkWindow*) &gdk_root_parent;
+
+  window_private = (GdkWindowPrivate*) window;
+  if (window_private->destroyed)
+    return NULL;
+
+  private = g_new0 (GdkWindowPrivate, 1);
+  pixmap = (GdkPixmap*) private;
+
+  private->parent = NULL;
+  private->window_type = GDK_WINDOW_PIXMAP;
+  private->x = 0;
+  private->y = 0;
+  private->width = width;
+  private->height = height;
+  private->resize_count = 0;
+  private->ref_count = 1;
+  private->destroyed = FALSE;
+
+  bpl = ((width - 1) / 8 + 1);
+  aligned_bpl = ((bpl - 1) / 2 + 1) * 2;
+  bits = g_malloc (aligned_bpl * height);
+  for (i = 0; i < height; i++)
+    for (j = 0; j < bpl; j++)
+      bits[i*aligned_bpl + j] = mirror[(guchar) data[i*bpl + j]];
+  private->xwindow = CreateBitmap (width, height, 1, 1, bits);
+
+  GDK_NOTE (MISC, g_print ("gdk_bitmap_create_from_data: %dx%d = %#x\n",
+                          width, height, private->xwindow));
+
+  g_free (bits);
+
+  private->colormap = NULL;
+  gdk_xid_table_insert (&private->xwindow, pixmap);
+
+  return pixmap;
+}
+
+GdkPixmap*
+gdk_pixmap_create_from_data (GdkWindow   *window,
+                            const gchar *data,
+                            gint         width,
+                            gint         height,
+                            gint         depth,
+                            GdkColor    *fg,
+                            GdkColor    *bg)
+{
+  /* Oh wow. I struggled with dozens of lines of code trying to get
+   * this right using a monochrome Win32 bitmap created from data, and
+   * a colour DIB section as the result, trying setting pens,
+   * background colors, whatnot and BitBlt:ing.  Nope. Then finally I
+   * realized it's much easier to do it using gdk...:
+   */
+
+  GdkPixmap *result = gdk_pixmap_new (window, width, height, depth);
+  GdkPixmap *source = gdk_bitmap_create_from_data (window, data, width, height);
+  GdkGC *gc = gdk_gc_new (result);
+  gdk_gc_set_foreground (gc, fg);
+  gdk_gc_set_background (gc, bg);
+  gdk_draw_pixmap (result, gc, source, 0, 0, 0, 0, width, height);
+  gdk_pixmap_unref (source);
+  gdk_gc_unref (gc);
+
+  GDK_NOTE (MISC, g_print ("gdk_pixmap_create_from_data: %dx%dx%d = %#x\n",
+                          width, height, depth,
+                          ((GdkPixmapPrivate *) result)->xwindow));
+  return result;
+}
+
+static gint
+gdk_pixmap_seek_string (FILE  *infile,
+                        const gchar *str,
+                        gint   skip_comments)
+{
+  char instr[1024];
+
+  while (!feof (infile))
+    {
+      fscanf (infile, "%1023s", instr);
+      if (skip_comments == TRUE && strcmp (instr, "/*") == 0)
+        {
+          fscanf (infile, "%1023s", instr);
+          while (!feof (infile) && strcmp (instr, "*/") != 0)
+            fscanf (infile, "%1023s", instr);
+          fscanf(infile, "%1023s", instr);
+        }
+      if (strcmp (instr, str)==0)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gint
+gdk_pixmap_seek_char (FILE  *infile,
+                      gchar  c)
+{
+  gint b, oldb;
+
+  while ((b = getc(infile)) != EOF)
+    {
+      if (c != b && b == '/')
+       {
+         b = getc (infile);
+         if (b == EOF)
+           return FALSE;
+         else if (b == '*')    /* we have a comment */
+           {
+             b = -1;
+             do
+               {
+                 oldb = b;
+                 b = getc (infile);
+                 if (b == EOF)
+                   return FALSE;
+               }
+             while (!(oldb == '*' && b == '/'));
+           }
+        }
+      else if (c == b)
+       return TRUE;
+    }
+  return FALSE;
+}
+
+static gint
+gdk_pixmap_read_string (FILE  *infile,
+                        gchar **buffer,
+                       guint *buffer_size)
+{
+  gint c;
+  guint cnt = 0, bufsiz, ret = FALSE;
+  gchar *buf;
+
+  buf = *buffer;
+  bufsiz = *buffer_size;
+  if (buf == NULL)
+    {
+      bufsiz = 10 * sizeof (gchar);
+      buf = g_new(gchar, bufsiz);
+    }
+
+  do
+    c = getc (infile);
+  while (c != EOF && c != '"');
+
+  if (c != '"')
+    goto out;
+
+  while ((c = getc(infile)) != EOF)
+    {
+      if (cnt == bufsiz)
+       {
+         guint new_size = bufsiz * 2;
+         if (new_size > bufsiz)
+           bufsiz = new_size;
+         else
+           goto out;
+       
+         buf = (gchar *) g_realloc (buf, bufsiz);
+         buf[bufsiz-1] = '\0';
+       }
+
+      if (c != '"')
+        buf[cnt++] = c;
+      else
+        {
+          buf[cnt] = 0;
+         ret = TRUE;
+         break;
+        }
+    }
+
+ out:
+  buf[bufsiz-1] = '\0';                /* ensure null termination for errors */
+  *buffer = buf;
+  *buffer_size = bufsiz;
+  return ret;
+}
+
+static gchar*
+gdk_pixmap_skip_whitespaces (gchar *buffer)
+{
+  gint32 index = 0;
+
+  while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09))
+    index++;
+
+  return &buffer[index];
+}
+
+static gchar*
+gdk_pixmap_skip_string (gchar *buffer)
+{
+  gint32 index = 0;
+
+  while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09)
+    index++;
+
+  return &buffer[index];
+}
+
+#define MAX_COLOR_LEN 120
+
+static gchar*
+gdk_pixmap_extract_color (gchar *buffer)
+{
+  gint counter, numnames;
+  gchar *ptr = NULL, ch, temp[128];
+  gchar color[MAX_COLOR_LEN], *retcol;
+  gint space;
+
+  counter = 0;
+  while (ptr == NULL)
+    {
+      if (buffer[counter] == 'c')
+        {
+          ch = buffer[counter + 1];
+          if (ch == 0x20 || ch == 0x09)
+            ptr = &buffer[counter + 1];
+        }
+      else if (buffer[counter] == 0)
+        return NULL;
+
+      counter++;
+    }
+
+  ptr = gdk_pixmap_skip_whitespaces (ptr);
+
+  if (ptr[0] == 0)
+    return NULL;
+  else if (ptr[0] == '#')
+    {
+      counter = 1;
+      while (ptr[counter] != 0 &&
+             ((ptr[counter] >= '0' && ptr[counter] <= '9') ||
+              (ptr[counter] >= 'a' && ptr[counter] <= 'f') ||
+              (ptr[counter] >= 'A' && ptr[counter] <= 'F')))
+        counter++;
+
+      retcol = g_new (gchar, counter+1);
+      strncpy (retcol, ptr, counter);
+
+      retcol[counter] = 0;
+
+      return retcol;
+    }
+
+  color[0] = 0;
+  numnames = 0;
+
+  space = MAX_COLOR_LEN - 1;
+  while (space > 0)
+    {
+      sscanf (ptr, "%127s", temp);
+
+      if (((gint)ptr[0] == 0) ||
+         (strcmp ("s", temp) == 0) || (strcmp ("m", temp) == 0) ||
+          (strcmp ("g", temp) == 0) || (strcmp ("g4", temp) == 0))
+       {
+         break;
+       }
+      else
+        {
+          if (numnames > 0)
+           {
+             space -= 1;
+             strcat (color, " ");
+           }
+         strncat (color, temp, space);
+         space -= MIN (space, strlen (temp));
+          ptr = gdk_pixmap_skip_string (ptr);
+          ptr = gdk_pixmap_skip_whitespaces (ptr);
+          numnames++;
+        }
+    }
+
+  retcol = g_strdup (color);
+  return retcol;
+}
+
+
+enum buffer_op
+{
+  op_header,
+  op_cmap,
+  op_body
+};
+
+
+static void
+gdk_xpm_destroy_notify (gpointer data)
+{
+  _GdkPixmapInfo *info = (_GdkPixmapInfo *)data;
+  GdkColor color;
+  int i;
+
+  for (i=0; i<info->ncolors; i++)
+    {
+      color.pixel = info->pixels[i];
+      gdk_colormap_free_colors (info->colormap, &color, 1);
+    }
+
+  gdk_colormap_unref (info->colormap);
+  g_free (info);
+}
+
+static GdkPixmap *
+_gdk_pixmap_create_from_xpm (GdkWindow  *window,
+                            GdkColormap *colormap,
+                            GdkBitmap **mask,
+                            GdkColor   *transparent_color,
+                            gchar *   (*get_buf) (enum buffer_op op,
+                                                  gpointer       handle),
+                            gpointer    handle)
+{
+  GdkPixmap *pixmap = NULL;
+  GdkImage *image = NULL;
+  GdkVisual *visual;
+  GdkGC *gc = NULL;
+  GdkColor tmp_color;
+  gint width, height, num_cols, cpp, n, ns, cnt, xcnt, ycnt, wbytes;
+  gchar *buffer, pixel_str[32];
+  gchar *name_buf;
+  _GdkPixmapColor *color = NULL, *fallbackcolor = NULL;
+  _GdkPixmapColor *colors = NULL;
+  gulong index;
+  GHashTable *color_hash = NULL;
+  _GdkPixmapInfo *color_info = NULL;
+
+  if ((window == NULL) && (colormap == NULL))
+    g_warning ("Creating pixmap from xpm with NULL window and colormap");
+
+  if (window == NULL)
+    window = (GdkWindow *)&gdk_root_parent;
+
+  if (colormap == NULL)
+    {
+      colormap = gdk_window_get_colormap (window);
+      visual = gdk_window_get_visual (window);
+    }
+  else
+    visual = ((GdkColormapPrivate *)colormap)->visual;
+
+  buffer = (*get_buf) (op_header, handle);
+  if (buffer == NULL)
+    return NULL;
+
+  sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp);
+  if (cpp >= 32)
+    {
+      g_warning ("Pixmap has more than 31 characters per color");
+      return NULL;
+    }
+
+  color_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+  if (transparent_color == NULL)
+    {
+      gdk_color_white (colormap, &tmp_color);
+      transparent_color = &tmp_color;
+    }
+
+  /* For pseudo-color and grayscale visuals, we have to remember
+   * the colors we allocated, so we can free them later.
+   */
+  if ((visual->type == GDK_VISUAL_PSEUDO_COLOR) ||
+      (visual->type == GDK_VISUAL_GRAYSCALE))
+    {
+      color_info = g_malloc (sizeof (_GdkPixmapInfo) +
+                            sizeof(gulong) * (num_cols - 1));
+      color_info->ncolors = num_cols;
+      color_info->colormap = colormap;
+      gdk_colormap_ref (colormap);
+    }
+
+  name_buf = g_new (gchar, num_cols * (cpp+1));
+  colors = g_new (_GdkPixmapColor, num_cols);
+
+  for (cnt = 0; cnt < num_cols; cnt++)
+    {
+      gchar *color_name;
+
+      buffer = (*get_buf) (op_cmap, handle);
+      if (buffer == NULL)
+       goto error;
+
+      color = &colors[cnt];
+      color->color_string = &name_buf [cnt * (cpp + 1)];
+      strncpy (color->color_string, buffer, cpp);
+      color->color_string[cpp] = 0;
+      buffer += strlen (color->color_string);
+      color->transparent = FALSE;
+
+      color_name = gdk_pixmap_extract_color (buffer);
+
+      if (color_name == NULL ||
+         gdk_color_parse (color_name, &color->color) == FALSE)
+       {
+         color->color = *transparent_color;
+         color->transparent = TRUE;
+       }
+
+      g_free (color_name);
+
+      /* FIXME: The remaining slowness appears to happen in this
+         function. */
+      gdk_color_alloc (colormap, &color->color);
+
+      if (color_info)
+       color_info->pixels[cnt] = color->color.pixel;
+
+      g_hash_table_insert (color_hash, color->color_string, color);
+      if (cnt == 0)
+       fallbackcolor = color;
+    }
+
+  index = 0;
+  image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height);
+
+  if (mask)
+    {
+      /* The pixmap mask is just a bits pattern.
+       * Color 0 is used for background and 1 for foreground.
+       * We don't care about the colormap, we just need 0 and 1.
+       */
+      GdkColor mask_pattern;
+
+      *mask = gdk_pixmap_new (window, width, height, 1);
+      gc = gdk_gc_new (*mask);
+
+      mask_pattern.pixel = 0;
+      gdk_gc_set_foreground (gc, &mask_pattern);
+      gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1);
+
+      mask_pattern.pixel = 1;
+      gdk_gc_set_foreground (gc, &mask_pattern);
+    }
+
+  wbytes = width * cpp;
+  for (ycnt = 0; ycnt < height; ycnt++)
+    {
+      buffer = (*get_buf) (op_body, handle);
+
+      /* FIXME: this slows things down a little - it could be
+       * integrated into the strncpy below, perhaps. OTOH, strlen
+       * is fast.
+       */
+      if ((buffer == NULL) || strlen (buffer) < wbytes)
+       continue;
+
+      for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++)
+       {
+         strncpy (pixel_str, &buffer[n], cpp);
+         pixel_str[cpp] = 0;
+         ns = 0;
+       
+         color = g_hash_table_lookup (color_hash, pixel_str);
+       
+         if (!color) /* screwed up XPM file */
+           color = fallbackcolor;
+       
+         gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel);
+       
+         if (mask && color->transparent)
+           {
+             if (cnt < xcnt)
+               gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
+             cnt = xcnt + 1;
+           }
+       }
+
+      if (mask && (cnt < xcnt))
+       gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
+    }
+
+ error:
+
+  if (mask)
+    gdk_gc_destroy (gc);
+
+  if (image != NULL)
+    {
+      pixmap = gdk_pixmap_new (window, width, height, visual->depth);
+
+      if (color_info)
+       gdk_drawable_set_data (pixmap, "gdk-xpm", color_info,
+                              gdk_xpm_destroy_notify);
+
+      gc = gdk_gc_new (pixmap);
+      gdk_gc_set_foreground (gc, transparent_color);
+      gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
+      gdk_gc_destroy (gc);
+      gdk_image_destroy (image);
+    }
+  else if (color_info)
+    gdk_xpm_destroy_notify (color_info);
+
+  if (color_hash != NULL)
+    g_hash_table_destroy (color_hash);
+
+  if (colors != NULL)
+    g_free (colors);
+
+  if (name_buf != NULL)
+    g_free (name_buf);
+
+  return pixmap;
+}
+
+
+struct file_handle
+{
+  FILE *infile;
+  gchar *buffer;
+  guint buffer_size;
+};
+
+
+static gchar *
+file_buffer (enum buffer_op op, gpointer handle)
+{
+  struct file_handle *h = handle;
+
+  switch (op)
+    {
+    case op_header:
+      if (gdk_pixmap_seek_string (h->infile, "XPM", FALSE) != TRUE)
+       break;
+
+      if (gdk_pixmap_seek_char (h->infile,'{') != TRUE)
+       break;
+      /* Fall through to the next gdk_pixmap_seek_char. */
+
+    case op_cmap:
+      gdk_pixmap_seek_char (h->infile, '"');
+      fseek (h->infile, -1, SEEK_CUR);
+      /* Fall through to the gdk_pixmap_read_string. */
+
+    case op_body:
+      gdk_pixmap_read_string (h->infile, &h->buffer, &h->buffer_size);
+      return h->buffer;
+    }
+  return 0;
+}
+
+GdkPixmap*
+gdk_pixmap_colormap_create_from_xpm (GdkWindow   *window,
+                                    GdkColormap *colormap,
+                                    GdkBitmap  **mask,
+                                    GdkColor    *transparent_color,
+                                    const gchar *filename)
+{
+  struct file_handle h;
+  GdkPixmap *pixmap = NULL;
+
+  memset (&h, 0, sizeof (h));
+  h.infile = fopen (filename, "rb");
+  if (h.infile != NULL)
+    {
+      pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
+                                           transparent_color,
+                                           file_buffer, &h);
+      fclose (h.infile);
+      g_free (h.buffer);
+    }
+
+  return pixmap;
+}
+
+GdkPixmap*
+gdk_pixmap_create_from_xpm (GdkWindow  *window,
+                           GdkBitmap **mask,
+                           GdkColor   *transparent_color,
+                           const gchar *filename)
+{
+  return gdk_pixmap_colormap_create_from_xpm (window, NULL, mask,
+                                      transparent_color, filename);
+}
+
+struct mem_handle
+{
+  gchar **data;
+  int offset;
+};
+
+
+static gchar *
+mem_buffer (enum buffer_op op, gpointer handle)
+{
+  struct mem_handle *h = handle;
+  switch (op)
+    {
+    case op_header:
+    case op_cmap:
+    case op_body:
+      if (h->data[h->offset])
+       return h->data[h->offset ++];
+    }
+  return 0;
+}
+
+GdkPixmap*
+gdk_pixmap_colormap_create_from_xpm_d (GdkWindow  *window,
+                                      GdkColormap *colormap,
+                                      GdkBitmap **mask,
+                                      GdkColor   *transparent_color,
+                                      gchar     **data)
+{
+  struct mem_handle h;
+  GdkPixmap *pixmap = NULL;
+
+  memset (&h, 0, sizeof (h));
+  h.data = data;
+  pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
+                                       transparent_color,
+                                       mem_buffer, &h);
+  return pixmap;
+}
+
+GdkPixmap*
+gdk_pixmap_create_from_xpm_d (GdkWindow  *window,
+                             GdkBitmap **mask,
+                             GdkColor   *transparent_color,
+                             gchar     **data)
+{
+  return gdk_pixmap_colormap_create_from_xpm_d (window, NULL, mask,
+                                               transparent_color, data);
+}
+
+GdkPixmap*
+gdk_pixmap_foreign_new (guint32 anid)
+{
+  GdkPixmap *pixmap;
+  GdkWindowPrivate *window_private;
+  GdkWindowPrivate *private;
+  HBITMAP xpixmap;
+  SIZE size;
+  unsigned int x_ret, y_ret, w_ret, h_ret, bw_ret, depth_ret;
+
+  /* check to make sure we were passed something at
+     least a little sane */
+  g_return_val_if_fail((anid != 0), NULL);
+
+  /* set the pixmap to the passed in value */
+  xpixmap = (HBITMAP) anid;
+  /* get the root window */
+  window_private = &gdk_root_parent;
+
+  /* get information about the BITMAP to fill in the structure for
+     the gdk window */
+  GetBitmapDimensionEx (xpixmap, &size);
+  w_ret = size.cx;
+  h_ret = size.cy;
+
+  /* allocate a new gdk pixmap */
+  private = g_new(GdkWindowPrivate, 1);
+  pixmap = (GdkPixmap *)private;
+
+  private->window_type = GDK_WINDOW_PIXMAP;
+  private->xwindow = xpixmap;
+  private->colormap = NULL;
+  private->parent = NULL;
+  private->x = 0;
+  private->y = 0;
+  private->width = w_ret;
+  private->height = h_ret;
+  private->resize_count = 0;
+  private->ref_count = 1;
+  private->destroyed = 0;
+
+  gdk_xid_table_insert(&private->xwindow, pixmap);
+
+  return pixmap;
+}
+
+GdkPixmap*
+gdk_pixmap_ref (GdkPixmap *pixmap)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap;
+  g_return_val_if_fail (pixmap != NULL, NULL);
+
+  private->ref_count += 1;
+  return pixmap;
+}
+
+void
+gdk_pixmap_unref (GdkPixmap *pixmap)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap;
+  g_return_if_fail(pixmap != NULL);
+
+  private->ref_count -= 1;
+
+  GDK_NOTE (MISC, g_print ("gdk_pixmap_unref: %#x %d%s\n",
+                          private->xwindow, private->ref_count,
+                          (private->ref_count == 0 ? " freeing" : "")));
+
+  if (private->ref_count == 0)
+    {
+      if (!DeleteObject (private->xwindow))
+       g_warning ("gdk_pixmap_unref: DeleteObject failed");
+      gdk_xid_table_remove (private->xwindow);
+      g_dataset_destroy (private);
+      g_free (private);
+    }
+}
+
+GdkBitmap *
+gdk_bitmap_ref (GdkBitmap *bitmap)
+{
+  return (GdkBitmap *)gdk_pixmap_ref ((GdkPixmap *)bitmap);
+}
+
+void
+gdk_bitmap_unref (GdkBitmap *bitmap)
+{
+  gdk_pixmap_unref ((GdkPixmap *)bitmap);
+}
diff --git a/gdk/win32/gdkpixmap.c b/gdk/win32/gdkpixmap.c
new file mode 100644 (file)
index 0000000..e8a6c02
--- /dev/null
@@ -0,0 +1,1059 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-1999 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gdk.h"
+#include "gdkprivate.h"
+
+typedef struct
+{
+  gchar *color_string;
+  GdkColor color;
+  gint transparent;
+} _GdkPixmapColor;
+
+typedef struct
+{
+  guint ncolors;
+  GdkColormap *colormap;
+  gulong pixels[1];
+} _GdkPixmapInfo;
+
+GdkPixmap*
+gdk_pixmap_new (GdkWindow *window,
+               gint       width,
+               gint       height,
+               gint       depth)
+{
+  GdkPixmap *pixmap;
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *window_private;
+  struct {
+    BITMAPINFOHEADER bmiHeader;
+    union {
+      WORD bmiIndices[256];
+      DWORD bmiMasks[3];
+      RGBQUAD bmiColors[256];
+    } u;
+  } bmi;
+  UINT iUsage;
+  HDC hdc;
+  GdkVisual *visual;
+  guchar *bits;
+  gint i;
+
+  g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
+  g_return_val_if_fail ((width != 0) && (height != 0), NULL);
+
+  if (!window)
+    window = (GdkWindow*) &gdk_root_parent;
+
+  window_private = (GdkWindowPrivate*) window;
+  if (window_private->destroyed)
+    return NULL;
+
+  if (depth == -1)
+    depth = gdk_window_get_visual (window)->depth;
+
+  GDK_NOTE (MISC, g_print ("gdk_pixmap_new: %dx%dx%d\n", width, height, depth));
+
+  private = g_new0 (GdkWindowPrivate, 1);
+  pixmap = (GdkPixmap*) private;
+
+  private->window_type = GDK_WINDOW_PIXMAP;
+
+  visual = gdk_window_get_visual (window);
+
+#if 0
+  if (depth == 1)
+    {
+      if ((private->xwindow =
+          CreateBitmap (width, height, 1, 1, NULL)) == NULL)
+       {
+         g_warning ("gdk_pixmap_new: CreateBitmap failed");
+         g_free (private);
+         return NULL;
+       }
+
+      private->colormap = NULL;
+    }
+  else
+    {
+      if (depth != visual->depth)
+       g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d",
+                  depth, visual->depth);
+
+      if ((hdc = GetDC (window_private->xwindow)) == NULL)
+       {
+         g_warning ("gdk_pixmap_new: GetDC failed");
+         g_free (private);
+         return NULL;
+       }
+
+      if ((private->xwindow =
+          CreateCompatibleBitmap (hdc, width, height)) == NULL)
+       {
+         g_warning ("gdk_pixmap_new: %dx%d CreateCompatibleBitmap failed",
+                    width, height);
+         ReleaseDC (window_private->xwindow, hdc);
+         g_free (private);
+         return NULL;
+       }
+
+      ReleaseDC (window_private->xwindow, hdc);
+
+      private->colormap = window_private->colormap;
+      if (private->colormap == NULL)
+       private->colormap = gdk_colormap_get_system ();
+    }
+#else
+
+  if ((hdc = GetDC (window_private->xwindow)) == NULL)
+    {
+      g_warning ("gdk_pixmap_new: GetDC failed");
+      g_free (private);
+      return NULL;
+    }
+
+  bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+  bmi.bmiHeader.biWidth = width;
+  bmi.bmiHeader.biHeight = -height;
+  bmi.bmiHeader.biPlanes = 1;
+  if (depth == 15)
+    bmi.bmiHeader.biBitCount = 16;
+  else
+    bmi.bmiHeader.biBitCount = depth;
+#if 1
+  if (depth == 16)
+    bmi.bmiHeader.biCompression = BI_BITFIELDS;
+  else
+#endif
+    bmi.bmiHeader.biCompression = BI_RGB;
+  bmi.bmiHeader.biSizeImage = 0;
+  bmi.bmiHeader.biXPelsPerMeter =
+    bmi.bmiHeader.biYPelsPerMeter = 0;
+  bmi.bmiHeader.biClrUsed = 0;
+  bmi.bmiHeader.biClrImportant = 0;
+
+  iUsage = DIB_RGB_COLORS;
+  if (depth == 1)
+    {
+      bmi.u.bmiColors[0].rgbBlue =
+       bmi.u.bmiColors[0].rgbGreen =
+       bmi.u.bmiColors[0].rgbRed = 0x00;
+      bmi.u.bmiColors[0].rgbReserved = 0x00;
+
+      bmi.u.bmiColors[1].rgbBlue =
+       bmi.u.bmiColors[1].rgbGreen =
+      bmi.u.bmiColors[1].rgbRed = 0xFF;
+      bmi.u.bmiColors[1].rgbReserved = 0x00;
+      private->colormap = NULL;
+    }
+  else
+    {
+      private->colormap = window_private->colormap;
+      if (private->colormap == NULL)
+       private->colormap = gdk_colormap_get_system ();
+
+      if (depth == 8)
+       {
+         iUsage = DIB_PAL_COLORS;
+         for (i = 0; i < 256; i++)
+           bmi.u.bmiIndices[i] = i;
+       }
+      else
+       {
+         if (depth != visual->depth)
+           g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d",
+                      depth, visual->depth);
+#if 1
+         if (depth == 16)
+           {
+             bmi.u.bmiMasks[0] = visual->red_mask;
+             bmi.u.bmiMasks[1] = visual->green_mask;
+             bmi.u.bmiMasks[2] = visual->blue_mask;
+           }
+#endif
+       }
+    }
+  if ((private->xwindow =
+       CreateDIBSection (hdc, (BITMAPINFO *) &bmi,
+                        iUsage, &bits, NULL, 0)) == NULL)
+    {
+      g_warning ("gdk_pixmap_new: CreateDIBSection failed: %d", GetLastError ());
+      ReleaseDC (window_private->xwindow, hdc);
+      g_free (private);
+      return NULL;
+    }
+  ReleaseDC (window_private->xwindow, hdc);
+
+#endif
+
+  GDK_NOTE (MISC, g_print ("... = %#x\n", private->xwindow));
+
+  private->parent = NULL;
+  private->x = 0;
+  private->y = 0;
+  private->width = width;
+  private->height = height;
+  private->resize_count = 0;
+  private->ref_count = 1;
+  private->destroyed = 0;
+
+  gdk_xid_table_insert (&private->xwindow, pixmap);
+
+  return pixmap;
+}
+
+GdkPixmap *
+gdk_pixmap_create_on_shared_image (GdkImage **image_return,
+                                  GdkWindow *window,
+                                  GdkVisual *visual,
+                                  gint       width,
+                                  gint       height,
+                                  gint       depth)
+{
+  GdkPixmap *pixmap;
+  GdkImagePrivate *image_private;
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *window_private;
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  window_private = (GdkWindowPrivate *) window;
+
+  if (depth == 1)
+    *image_return = gdk_image_bitmap_new (GDK_IMAGE_SHARED_PIXMAP, visual, width, height);
+  else
+    {
+      g_return_val_if_fail (depth == visual->depth, NULL);
+      *image_return = gdk_image_new (GDK_IMAGE_SHARED_PIXMAP, visual, width, height);
+    }
+
+  g_return_val_if_fail (*image_return != NULL, NULL);
+
+  image_private = (GdkImagePrivate *) *image_return;
+
+  private = g_new0 (GdkWindowPrivate, 1);
+  pixmap = (GdkPixmap*) private;
+
+  private->xwindow = image_private->ximage;
+  private->window_type = GDK_WINDOW_PIXMAP;
+  private->colormap = window_private->colormap;
+  private->parent = NULL;
+  private->x = 0;
+  private->y = 0;
+  private->width = width;
+  private->height = height;
+  private->resize_count = 0;
+  private->ref_count = 1;
+  private->destroyed = 0;
+
+  gdk_xid_table_insert (&private->xwindow, pixmap);
+
+  GDK_NOTE (MISC,
+           g_print ("gdk_pixmap_create_on_shared_image: %dx%dx%d = %#x\n",
+                    width, height, depth, private->xwindow));
+
+  return pixmap;
+}
+
+static unsigned char mirror[256] = {
+  0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+  0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+  0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+  0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+  0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+  0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+  0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+  0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+  0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+  0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+  0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+  0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+  0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+  0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+  0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+  0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+  0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+  0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+  0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+  0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+  0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+  0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+  0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+  0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+  0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+  0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+  0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+  0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+  0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+  0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+  0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+  0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+GdkPixmap *
+gdk_bitmap_create_from_data (GdkWindow   *window,
+                            const gchar *data,
+                            gint         width,
+                            gint         height)
+{
+  GdkPixmap *pixmap;
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *window_private;
+  gint i, j, bpl, aligned_bpl;
+  guchar *bits;
+
+  g_return_val_if_fail (data != NULL, NULL);
+  g_return_val_if_fail ((width != 0) && (height != 0), NULL);
+
+  if (!window)
+    window = (GdkWindow*) &gdk_root_parent;
+
+  window_private = (GdkWindowPrivate*) window;
+  if (window_private->destroyed)
+    return NULL;
+
+  private = g_new0 (GdkWindowPrivate, 1);
+  pixmap = (GdkPixmap*) private;
+
+  private->parent = NULL;
+  private->window_type = GDK_WINDOW_PIXMAP;
+  private->x = 0;
+  private->y = 0;
+  private->width = width;
+  private->height = height;
+  private->resize_count = 0;
+  private->ref_count = 1;
+  private->destroyed = FALSE;
+
+  bpl = ((width - 1) / 8 + 1);
+  aligned_bpl = ((bpl - 1) / 2 + 1) * 2;
+  bits = g_malloc (aligned_bpl * height);
+  for (i = 0; i < height; i++)
+    for (j = 0; j < bpl; j++)
+      bits[i*aligned_bpl + j] = mirror[(guchar) data[i*bpl + j]];
+  private->xwindow = CreateBitmap (width, height, 1, 1, bits);
+
+  GDK_NOTE (MISC, g_print ("gdk_bitmap_create_from_data: %dx%d = %#x\n",
+                          width, height, private->xwindow));
+
+  g_free (bits);
+
+  private->colormap = NULL;
+  gdk_xid_table_insert (&private->xwindow, pixmap);
+
+  return pixmap;
+}
+
+GdkPixmap*
+gdk_pixmap_create_from_data (GdkWindow   *window,
+                            const gchar *data,
+                            gint         width,
+                            gint         height,
+                            gint         depth,
+                            GdkColor    *fg,
+                            GdkColor    *bg)
+{
+  /* Oh wow. I struggled with dozens of lines of code trying to get
+   * this right using a monochrome Win32 bitmap created from data, and
+   * a colour DIB section as the result, trying setting pens,
+   * background colors, whatnot and BitBlt:ing.  Nope. Then finally I
+   * realized it's much easier to do it using gdk...:
+   */
+
+  GdkPixmap *result = gdk_pixmap_new (window, width, height, depth);
+  GdkPixmap *source = gdk_bitmap_create_from_data (window, data, width, height);
+  GdkGC *gc = gdk_gc_new (result);
+  gdk_gc_set_foreground (gc, fg);
+  gdk_gc_set_background (gc, bg);
+  gdk_draw_pixmap (result, gc, source, 0, 0, 0, 0, width, height);
+  gdk_pixmap_unref (source);
+  gdk_gc_unref (gc);
+
+  GDK_NOTE (MISC, g_print ("gdk_pixmap_create_from_data: %dx%dx%d = %#x\n",
+                          width, height, depth,
+                          ((GdkPixmapPrivate *) result)->xwindow));
+  return result;
+}
+
+static gint
+gdk_pixmap_seek_string (FILE  *infile,
+                        const gchar *str,
+                        gint   skip_comments)
+{
+  char instr[1024];
+
+  while (!feof (infile))
+    {
+      fscanf (infile, "%1023s", instr);
+      if (skip_comments == TRUE && strcmp (instr, "/*") == 0)
+        {
+          fscanf (infile, "%1023s", instr);
+          while (!feof (infile) && strcmp (instr, "*/") != 0)
+            fscanf (infile, "%1023s", instr);
+          fscanf(infile, "%1023s", instr);
+        }
+      if (strcmp (instr, str)==0)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gint
+gdk_pixmap_seek_char (FILE  *infile,
+                      gchar  c)
+{
+  gint b, oldb;
+
+  while ((b = getc(infile)) != EOF)
+    {
+      if (c != b && b == '/')
+       {
+         b = getc (infile);
+         if (b == EOF)
+           return FALSE;
+         else if (b == '*')    /* we have a comment */
+           {
+             b = -1;
+             do
+               {
+                 oldb = b;
+                 b = getc (infile);
+                 if (b == EOF)
+                   return FALSE;
+               }
+             while (!(oldb == '*' && b == '/'));
+           }
+        }
+      else if (c == b)
+       return TRUE;
+    }
+  return FALSE;
+}
+
+static gint
+gdk_pixmap_read_string (FILE  *infile,
+                        gchar **buffer,
+                       guint *buffer_size)
+{
+  gint c;
+  guint cnt = 0, bufsiz, ret = FALSE;
+  gchar *buf;
+
+  buf = *buffer;
+  bufsiz = *buffer_size;
+  if (buf == NULL)
+    {
+      bufsiz = 10 * sizeof (gchar);
+      buf = g_new(gchar, bufsiz);
+    }
+
+  do
+    c = getc (infile);
+  while (c != EOF && c != '"');
+
+  if (c != '"')
+    goto out;
+
+  while ((c = getc(infile)) != EOF)
+    {
+      if (cnt == bufsiz)
+       {
+         guint new_size = bufsiz * 2;
+         if (new_size > bufsiz)
+           bufsiz = new_size;
+         else
+           goto out;
+       
+         buf = (gchar *) g_realloc (buf, bufsiz);
+         buf[bufsiz-1] = '\0';
+       }
+
+      if (c != '"')
+        buf[cnt++] = c;
+      else
+        {
+          buf[cnt] = 0;
+         ret = TRUE;
+         break;
+        }
+    }
+
+ out:
+  buf[bufsiz-1] = '\0';                /* ensure null termination for errors */
+  *buffer = buf;
+  *buffer_size = bufsiz;
+  return ret;
+}
+
+static gchar*
+gdk_pixmap_skip_whitespaces (gchar *buffer)
+{
+  gint32 index = 0;
+
+  while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09))
+    index++;
+
+  return &buffer[index];
+}
+
+static gchar*
+gdk_pixmap_skip_string (gchar *buffer)
+{
+  gint32 index = 0;
+
+  while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09)
+    index++;
+
+  return &buffer[index];
+}
+
+#define MAX_COLOR_LEN 120
+
+static gchar*
+gdk_pixmap_extract_color (gchar *buffer)
+{
+  gint counter, numnames;
+  gchar *ptr = NULL, ch, temp[128];
+  gchar color[MAX_COLOR_LEN], *retcol;
+  gint space;
+
+  counter = 0;
+  while (ptr == NULL)
+    {
+      if (buffer[counter] == 'c')
+        {
+          ch = buffer[counter + 1];
+          if (ch == 0x20 || ch == 0x09)
+            ptr = &buffer[counter + 1];
+        }
+      else if (buffer[counter] == 0)
+        return NULL;
+
+      counter++;
+    }
+
+  ptr = gdk_pixmap_skip_whitespaces (ptr);
+
+  if (ptr[0] == 0)
+    return NULL;
+  else if (ptr[0] == '#')
+    {
+      counter = 1;
+      while (ptr[counter] != 0 &&
+             ((ptr[counter] >= '0' && ptr[counter] <= '9') ||
+              (ptr[counter] >= 'a' && ptr[counter] <= 'f') ||
+              (ptr[counter] >= 'A' && ptr[counter] <= 'F')))
+        counter++;
+
+      retcol = g_new (gchar, counter+1);
+      strncpy (retcol, ptr, counter);
+
+      retcol[counter] = 0;
+
+      return retcol;
+    }
+
+  color[0] = 0;
+  numnames = 0;
+
+  space = MAX_COLOR_LEN - 1;
+  while (space > 0)
+    {
+      sscanf (ptr, "%127s", temp);
+
+      if (((gint)ptr[0] == 0) ||
+         (strcmp ("s", temp) == 0) || (strcmp ("m", temp) == 0) ||
+          (strcmp ("g", temp) == 0) || (strcmp ("g4", temp) == 0))
+       {
+         break;
+       }
+      else
+        {
+          if (numnames > 0)
+           {
+             space -= 1;
+             strcat (color, " ");
+           }
+         strncat (color, temp, space);
+         space -= MIN (space, strlen (temp));
+          ptr = gdk_pixmap_skip_string (ptr);
+          ptr = gdk_pixmap_skip_whitespaces (ptr);
+          numnames++;
+        }
+    }
+
+  retcol = g_strdup (color);
+  return retcol;
+}
+
+
+enum buffer_op
+{
+  op_header,
+  op_cmap,
+  op_body
+};
+
+
+static void
+gdk_xpm_destroy_notify (gpointer data)
+{
+  _GdkPixmapInfo *info = (_GdkPixmapInfo *)data;
+  GdkColor color;
+  int i;
+
+  for (i=0; i<info->ncolors; i++)
+    {
+      color.pixel = info->pixels[i];
+      gdk_colormap_free_colors (info->colormap, &color, 1);
+    }
+
+  gdk_colormap_unref (info->colormap);
+  g_free (info);
+}
+
+static GdkPixmap *
+_gdk_pixmap_create_from_xpm (GdkWindow  *window,
+                            GdkColormap *colormap,
+                            GdkBitmap **mask,
+                            GdkColor   *transparent_color,
+                            gchar *   (*get_buf) (enum buffer_op op,
+                                                  gpointer       handle),
+                            gpointer    handle)
+{
+  GdkPixmap *pixmap = NULL;
+  GdkImage *image = NULL;
+  GdkVisual *visual;
+  GdkGC *gc = NULL;
+  GdkColor tmp_color;
+  gint width, height, num_cols, cpp, n, ns, cnt, xcnt, ycnt, wbytes;
+  gchar *buffer, pixel_str[32];
+  gchar *name_buf;
+  _GdkPixmapColor *color = NULL, *fallbackcolor = NULL;
+  _GdkPixmapColor *colors = NULL;
+  gulong index;
+  GHashTable *color_hash = NULL;
+  _GdkPixmapInfo *color_info = NULL;
+
+  if ((window == NULL) && (colormap == NULL))
+    g_warning ("Creating pixmap from xpm with NULL window and colormap");
+
+  if (window == NULL)
+    window = (GdkWindow *)&gdk_root_parent;
+
+  if (colormap == NULL)
+    {
+      colormap = gdk_window_get_colormap (window);
+      visual = gdk_window_get_visual (window);
+    }
+  else
+    visual = ((GdkColormapPrivate *)colormap)->visual;
+
+  buffer = (*get_buf) (op_header, handle);
+  if (buffer == NULL)
+    return NULL;
+
+  sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp);
+  if (cpp >= 32)
+    {
+      g_warning ("Pixmap has more than 31 characters per color");
+      return NULL;
+    }
+
+  color_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+  if (transparent_color == NULL)
+    {
+      gdk_color_white (colormap, &tmp_color);
+      transparent_color = &tmp_color;
+    }
+
+  /* For pseudo-color and grayscale visuals, we have to remember
+   * the colors we allocated, so we can free them later.
+   */
+  if ((visual->type == GDK_VISUAL_PSEUDO_COLOR) ||
+      (visual->type == GDK_VISUAL_GRAYSCALE))
+    {
+      color_info = g_malloc (sizeof (_GdkPixmapInfo) +
+                            sizeof(gulong) * (num_cols - 1));
+      color_info->ncolors = num_cols;
+      color_info->colormap = colormap;
+      gdk_colormap_ref (colormap);
+    }
+
+  name_buf = g_new (gchar, num_cols * (cpp+1));
+  colors = g_new (_GdkPixmapColor, num_cols);
+
+  for (cnt = 0; cnt < num_cols; cnt++)
+    {
+      gchar *color_name;
+
+      buffer = (*get_buf) (op_cmap, handle);
+      if (buffer == NULL)
+       goto error;
+
+      color = &colors[cnt];
+      color->color_string = &name_buf [cnt * (cpp + 1)];
+      strncpy (color->color_string, buffer, cpp);
+      color->color_string[cpp] = 0;
+      buffer += strlen (color->color_string);
+      color->transparent = FALSE;
+
+      color_name = gdk_pixmap_extract_color (buffer);
+
+      if (color_name == NULL ||
+         gdk_color_parse (color_name, &color->color) == FALSE)
+       {
+         color->color = *transparent_color;
+         color->transparent = TRUE;
+       }
+
+      g_free (color_name);
+
+      /* FIXME: The remaining slowness appears to happen in this
+         function. */
+      gdk_color_alloc (colormap, &color->color);
+
+      if (color_info)
+       color_info->pixels[cnt] = color->color.pixel;
+
+      g_hash_table_insert (color_hash, color->color_string, color);
+      if (cnt == 0)
+       fallbackcolor = color;
+    }
+
+  index = 0;
+  image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height);
+
+  if (mask)
+    {
+      /* The pixmap mask is just a bits pattern.
+       * Color 0 is used for background and 1 for foreground.
+       * We don't care about the colormap, we just need 0 and 1.
+       */
+      GdkColor mask_pattern;
+
+      *mask = gdk_pixmap_new (window, width, height, 1);
+      gc = gdk_gc_new (*mask);
+
+      mask_pattern.pixel = 0;
+      gdk_gc_set_foreground (gc, &mask_pattern);
+      gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1);
+
+      mask_pattern.pixel = 1;
+      gdk_gc_set_foreground (gc, &mask_pattern);
+    }
+
+  wbytes = width * cpp;
+  for (ycnt = 0; ycnt < height; ycnt++)
+    {
+      buffer = (*get_buf) (op_body, handle);
+
+      /* FIXME: this slows things down a little - it could be
+       * integrated into the strncpy below, perhaps. OTOH, strlen
+       * is fast.
+       */
+      if ((buffer == NULL) || strlen (buffer) < wbytes)
+       continue;
+
+      for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++)
+       {
+         strncpy (pixel_str, &buffer[n], cpp);
+         pixel_str[cpp] = 0;
+         ns = 0;
+       
+         color = g_hash_table_lookup (color_hash, pixel_str);
+       
+         if (!color) /* screwed up XPM file */
+           color = fallbackcolor;
+       
+         gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel);
+       
+         if (mask && color->transparent)
+           {
+             if (cnt < xcnt)
+               gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
+             cnt = xcnt + 1;
+           }
+       }
+
+      if (mask && (cnt < xcnt))
+       gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
+    }
+
+ error:
+
+  if (mask)
+    gdk_gc_destroy (gc);
+
+  if (image != NULL)
+    {
+      pixmap = gdk_pixmap_new (window, width, height, visual->depth);
+
+      if (color_info)
+       gdk_drawable_set_data (pixmap, "gdk-xpm", color_info,
+                              gdk_xpm_destroy_notify);
+
+      gc = gdk_gc_new (pixmap);
+      gdk_gc_set_foreground (gc, transparent_color);
+      gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
+      gdk_gc_destroy (gc);
+      gdk_image_destroy (image);
+    }
+  else if (color_info)
+    gdk_xpm_destroy_notify (color_info);
+
+  if (color_hash != NULL)
+    g_hash_table_destroy (color_hash);
+
+  if (colors != NULL)
+    g_free (colors);
+
+  if (name_buf != NULL)
+    g_free (name_buf);
+
+  return pixmap;
+}
+
+
+struct file_handle
+{
+  FILE *infile;
+  gchar *buffer;
+  guint buffer_size;
+};
+
+
+static gchar *
+file_buffer (enum buffer_op op, gpointer handle)
+{
+  struct file_handle *h = handle;
+
+  switch (op)
+    {
+    case op_header:
+      if (gdk_pixmap_seek_string (h->infile, "XPM", FALSE) != TRUE)
+       break;
+
+      if (gdk_pixmap_seek_char (h->infile,'{') != TRUE)
+       break;
+      /* Fall through to the next gdk_pixmap_seek_char. */
+
+    case op_cmap:
+      gdk_pixmap_seek_char (h->infile, '"');
+      fseek (h->infile, -1, SEEK_CUR);
+      /* Fall through to the gdk_pixmap_read_string. */
+
+    case op_body:
+      gdk_pixmap_read_string (h->infile, &h->buffer, &h->buffer_size);
+      return h->buffer;
+    }
+  return 0;
+}
+
+GdkPixmap*
+gdk_pixmap_colormap_create_from_xpm (GdkWindow   *window,
+                                    GdkColormap *colormap,
+                                    GdkBitmap  **mask,
+                                    GdkColor    *transparent_color,
+                                    const gchar *filename)
+{
+  struct file_handle h;
+  GdkPixmap *pixmap = NULL;
+
+  memset (&h, 0, sizeof (h));
+  h.infile = fopen (filename, "rb");
+  if (h.infile != NULL)
+    {
+      pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
+                                           transparent_color,
+                                           file_buffer, &h);
+      fclose (h.infile);
+      g_free (h.buffer);
+    }
+
+  return pixmap;
+}
+
+GdkPixmap*
+gdk_pixmap_create_from_xpm (GdkWindow  *window,
+                           GdkBitmap **mask,
+                           GdkColor   *transparent_color,
+                           const gchar *filename)
+{
+  return gdk_pixmap_colormap_create_from_xpm (window, NULL, mask,
+                                      transparent_color, filename);
+}
+
+struct mem_handle
+{
+  gchar **data;
+  int offset;
+};
+
+
+static gchar *
+mem_buffer (enum buffer_op op, gpointer handle)
+{
+  struct mem_handle *h = handle;
+  switch (op)
+    {
+    case op_header:
+    case op_cmap:
+    case op_body:
+      if (h->data[h->offset])
+       return h->data[h->offset ++];
+    }
+  return 0;
+}
+
+GdkPixmap*
+gdk_pixmap_colormap_create_from_xpm_d (GdkWindow  *window,
+                                      GdkColormap *colormap,
+                                      GdkBitmap **mask,
+                                      GdkColor   *transparent_color,
+                                      gchar     **data)
+{
+  struct mem_handle h;
+  GdkPixmap *pixmap = NULL;
+
+  memset (&h, 0, sizeof (h));
+  h.data = data;
+  pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
+                                       transparent_color,
+                                       mem_buffer, &h);
+  return pixmap;
+}
+
+GdkPixmap*
+gdk_pixmap_create_from_xpm_d (GdkWindow  *window,
+                             GdkBitmap **mask,
+                             GdkColor   *transparent_color,
+                             gchar     **data)
+{
+  return gdk_pixmap_colormap_create_from_xpm_d (window, NULL, mask,
+                                               transparent_color, data);
+}
+
+GdkPixmap*
+gdk_pixmap_foreign_new (guint32 anid)
+{
+  GdkPixmap *pixmap;
+  GdkWindowPrivate *window_private;
+  GdkWindowPrivate *private;
+  HBITMAP xpixmap;
+  SIZE size;
+  unsigned int x_ret, y_ret, w_ret, h_ret, bw_ret, depth_ret;
+
+  /* check to make sure we were passed something at
+     least a little sane */
+  g_return_val_if_fail((anid != 0), NULL);
+
+  /* set the pixmap to the passed in value */
+  xpixmap = (HBITMAP) anid;
+  /* get the root window */
+  window_private = &gdk_root_parent;
+
+  /* get information about the BITMAP to fill in the structure for
+     the gdk window */
+  GetBitmapDimensionEx (xpixmap, &size);
+  w_ret = size.cx;
+  h_ret = size.cy;
+
+  /* allocate a new gdk pixmap */
+  private = g_new(GdkWindowPrivate, 1);
+  pixmap = (GdkPixmap *)private;
+
+  private->window_type = GDK_WINDOW_PIXMAP;
+  private->xwindow = xpixmap;
+  private->colormap = NULL;
+  private->parent = NULL;
+  private->x = 0;
+  private->y = 0;
+  private->width = w_ret;
+  private->height = h_ret;
+  private->resize_count = 0;
+  private->ref_count = 1;
+  private->destroyed = 0;
+
+  gdk_xid_table_insert(&private->xwindow, pixmap);
+
+  return pixmap;
+}
+
+GdkPixmap*
+gdk_pixmap_ref (GdkPixmap *pixmap)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap;
+  g_return_val_if_fail (pixmap != NULL, NULL);
+
+  private->ref_count += 1;
+  return pixmap;
+}
+
+void
+gdk_pixmap_unref (GdkPixmap *pixmap)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap;
+  g_return_if_fail(pixmap != NULL);
+
+  private->ref_count -= 1;
+
+  GDK_NOTE (MISC, g_print ("gdk_pixmap_unref: %#x %d%s\n",
+                          private->xwindow, private->ref_count,
+                          (private->ref_count == 0 ? " freeing" : "")));
+
+  if (private->ref_count == 0)
+    {
+      if (!DeleteObject (private->xwindow))
+       g_warning ("gdk_pixmap_unref: DeleteObject failed");
+      gdk_xid_table_remove (private->xwindow);
+      g_dataset_destroy (private);
+      g_free (private);
+    }
+}
+
+GdkBitmap *
+gdk_bitmap_ref (GdkBitmap *bitmap)
+{
+  return (GdkBitmap *)gdk_pixmap_ref ((GdkPixmap *)bitmap);
+}
+
+void
+gdk_bitmap_unref (GdkBitmap *bitmap)
+{
+  gdk_pixmap_unref ((GdkPixmap *)bitmap);
+}
diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h
new file mode 100644 (file)
index 0000000..e90da96
--- /dev/null
@@ -0,0 +1,420 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GDK_PRIVATE_H__
+#define __GDK_PRIVATE_H__
+
+#define STRICT                 /* We want strict type checks */
+#include <windows.h>
+
+#include <time.h>
+#include <gdk/gdktypes.h>
+
+/* Define corresponding Windows types for some X11 types, just for laziness.
+ */
+
+#include <glib.h>
+
+typedef HANDLE XID;
+typedef PALETTEENTRY XColor;
+typedef HDC GC;
+typedef ATOM Atom;
+typedef HCURSOR Cursor;
+typedef guint VisualID;
+typedef DWORD KeySym;
+typedef int Status;
+
+/* Define some of the X11 constants also here, again just for laziness */
+
+/* Generic null resource */
+#define None 0
+
+/* Error codes */
+#define Success            0
+
+/* Grabbing status */
+#define GrabSuccess       0
+#define AlreadyGrabbed    2
+
+/* For CreateColormap */
+#define AllocNone 0
+#define AllocAll 1
+
+/* Notify modes */
+#define NotifyNormal 0
+#define NotifyHint 1
+
+/* Some structs are somewhat useful to emulate internally, just to
+   keep the code less #ifdefed.  */
+typedef struct {
+  HPALETTE palette;            /* Palette handle used when drawing. */
+  guint size;                  /* Number of entries in the palette. */
+  gboolean stale;              /* 1 if palette needs to be realized,
+                                * otherwise 0. */
+  gboolean *in_use;
+  gboolean rc_palette;         /* If RC_PALETTE is on in the RASTERCAPS */
+  gulong sizepalette;          /* SIZEPALETTE if rc_palette */
+} ColormapStruct, *Colormap;
+  
+typedef struct {
+  gint map_entries;
+  guint visualid;
+  guint bitspixel;
+} Visual;
+
+typedef struct {
+  Colormap colormap;
+  unsigned long red_max;
+  unsigned long red_mult;
+  unsigned long green_max;
+  unsigned long green_mult;
+  unsigned long blue_max;
+  unsigned long blue_mult;
+  unsigned long base_pixel;
+} XStandardColormap;
+
+extern LRESULT CALLBACK 
+gdk_WindowProc (HWND, UINT, WPARAM, LPARAM);
+
+#define gdk_window_lookup(xid)    ((GdkWindow*) gdk_xid_table_lookup (xid))
+#define gdk_pixmap_lookup(xid)    ((GdkPixmap*) gdk_xid_table_lookup (xid))
+
+/* HFONTs clash with HWNDs, so add dithering to HFONTs... (hack) */
+#define HFONT_DITHER 43
+#define gdk_font_lookup(xid)      ((GdkFont*) gdk_xid_table_lookup ((HANDLE) ((guint) xid + HFONT_DITHER)))
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+typedef struct _GdkWindowPrivate       GdkWindowPrivate;
+typedef struct _GdkWindowPrivate       GdkPixmapPrivate;
+typedef struct _GdkImagePrivate               GdkImagePrivate;
+typedef struct _GdkGCPrivate          GdkGCPrivate;
+typedef struct _GdkColormapPrivate     GdkColormapPrivate;
+typedef struct _GdkColorInfo           GdkColorInfo;
+typedef struct _GdkVisualPrivate       GdkVisualPrivate;
+typedef struct _GdkFontPrivate        GdkFontPrivate;
+typedef struct _GdkCursorPrivate       GdkCursorPrivate;
+typedef struct _GdkEventFilter        GdkEventFilter;
+typedef struct _GdkClientFilter               GdkClientFilter;
+typedef struct _GdkColorContextPrivate GdkColorContextPrivate;
+typedef struct _GdkRegionPrivate       GdkRegionPrivate;
+
+
+struct _GdkWindowPrivate
+{
+  GdkWindow window;
+  GdkWindow *parent;
+  HANDLE xwindow;
+  gint16 x;
+  gint16 y;
+  guint16 width;
+  guint16 height;
+  guint8 resize_count;
+  guint8 window_type;
+  guint ref_count;
+  guint destroyed : 2;
+  guint mapped : 1;
+  guint guffaw_gravity : 1;
+
+  /* We must keep the event mask here to filter them ourselves */
+  gint event_mask;
+
+  /* Values for bg_type */
+#define GDK_WIN32_BG_NORMAL 0
+#define GDK_WIN32_BG_PIXEL 1
+#define GDK_WIN32_BG_PIXMAP 2
+#define GDK_WIN32_BG_PARENT_RELATIVE 3
+#define GDK_WIN32_BG_TRANSPARENT 4
+
+  /* We draw the background ourselves at WM_ERASEBKGND  */
+  guchar bg_type;
+  GdkColor bg_pixel;
+  GdkPixmap *bg_pixmap;
+
+  HCURSOR xcursor;
+
+  /* Window size hints */
+  gint hint_flags;
+  gint hint_x, hint_y;
+  gint hint_min_width, hint_min_height;
+  gint hint_max_width, hint_max_height;
+
+  gint extension_events;
+  gboolean extension_events_selected;
+
+  GList *filters;
+  GdkColormap *colormap;
+  GList *children;
+};
+
+struct _GdkImagePrivate
+{
+  GdkImage image;
+  HBITMAP ximage;
+  gpointer x_shm_info;
+
+  void (*image_put) (GdkDrawable *window,
+                    GdkGC       *gc,
+                    GdkImage    *image,
+                    gint         xsrc,
+                    gint         ysrc,
+                    gint         xdest,
+                    gint         ydest,
+                    gint         width,
+                    gint         height);
+};
+
+struct _GdkGCPrivate
+{
+  GdkGC gc;
+  GC xgc;
+  /* A Windows Device Context (DC) is not equivalent to an X11
+   * GC. We can use a DC only in the window for which it was
+   * allocated, or (in the case of a memory DC) with the bitmap that
+   * has been selected into it. Thus, we have to release and
+   * reallocate a DC each time the GdkGC is used to paint into a new
+   * window or pixmap. We thus keep all the necessary values in the
+   * GdkGCPrivate struct.
+   */
+  GdkGCValuesMask values_mask;
+  GdkColor foreground;
+  GdkColor background;
+  HFONT font;
+  gint rop2;
+  GdkFill fill_style;
+  GdkPixmap *tile;
+  GdkPixmap *stipple;
+  HRGN clip_region;
+  GdkSubwindowMode subwindow_mode;
+  gint ts_x_origin;
+  gint ts_y_origin;
+  gint clip_x_origin;
+  gint clip_y_origin;
+  gint graphics_exposures;
+  gint pen_width;
+  DWORD pen_style;
+  HANDLE hwnd;                 /* If a DC is allocated, for which window
+                                  or what bitmap is selected into it */
+  int saved_dc;
+  guint ref_count;
+};
+
+typedef enum {
+  GDK_COLOR_WRITEABLE = 1 << 0
+} GdkColorInfoFlags;
+
+struct _GdkColorInfo
+{
+  GdkColorInfoFlags flags;
+  guint ref_count;
+};
+
+struct _GdkColormapPrivate
+{
+  GdkColormap colormap;
+  Colormap xcolormap;
+  GdkVisual *visual;
+  gint private_val;
+
+  GHashTable *hash;
+  GdkColorInfo *info;
+  time_t last_sync_time;
+  
+  guint ref_count;
+};
+
+struct _GdkVisualPrivate
+{
+  GdkVisual visual;
+  Visual *xvisual;
+};
+
+struct _GdkFontPrivate
+{
+  GdkFont font;
+  /* XFontStruct *xfont; */
+  /* generic pointer point to XFontStruct or XFontSet */
+  /* in Win32 a HFONT */ 
+  gpointer xfont;
+  guint ref_count;
+};
+
+struct _GdkCursorPrivate
+{
+  GdkCursor cursor;
+  Cursor xcursor;
+};
+
+struct _GdkEventFilter {
+  GdkFilterFunc function;
+  gpointer data;
+};
+
+struct _GdkClientFilter {
+  GdkAtom       type;
+  GdkFilterFunc function;
+  gpointer      data;
+};
+
+#ifdef USE_XIM
+
+typedef struct _GdkICPrivate GdkICPrivate;
+
+struct _GdkICPrivate
+{
+  XIC xic;
+  GdkICAttr *attr;
+  GdkICAttributesType mask;
+};
+
+#endif /* USE_XIM */
+
+struct _GdkColorContextPrivate
+{
+  GdkColorContext color_context;
+  XStandardColormap std_cmap;
+};
+
+struct _GdkRegionPrivate
+{
+  GdkRegion region;
+  HRGN xregion;
+};
+
+typedef enum {
+  GDK_DEBUG_MISC          = 1 << 0,
+  GDK_DEBUG_EVENTS        = 1 << 1,
+  GDK_DEBUG_DND           = 1 << 2,
+  GDK_DEBUG_COLOR_CONTEXT = 1 << 3,
+  GDK_DEBUG_XIM           = 1 << 4,
+  GDK_DEBUG_SELECTION    = 1 << 5
+} GdkDebugFlag;
+
+void gdk_events_init (void);
+void gdk_window_init (void);
+void gdk_visual_init (void);
+void gdk_selection_init (void);
+void gdk_dnd_init    (void);
+void gdk_dnd_exit    (void);
+void gdk_image_init  (void);
+void gdk_image_exit  (void);
+
+GdkColormap* gdk_colormap_lookup (Colormap  xcolormap);
+GdkVisual*   gdk_visual_lookup  (Visual   *xvisual);
+
+void gdk_window_add_colormap_windows (GdkWindow *window);
+void gdk_window_destroy_notify      (GdkWindow *window);
+
+void    gdk_xid_table_insert (XID      *xid,
+                              gpointer  data);
+void    gdk_xid_table_remove (XID       xid);
+gpointer gdk_xid_table_lookup (XID      xid);
+
+/* Internal functions */
+
+HDC    gdk_gc_predraw  (GdkWindowPrivate *window_private,
+                        GdkGCPrivate *gc_private);
+void   gdk_gc_postdraw (GdkWindowPrivate *window_private,
+                        GdkGCPrivate *gc_private);
+HRGN   BitmapToRegion  (HBITMAP hBmp);
+
+void    gdk_sel_prop_store (GdkWindow *owner,
+                           GdkAtom    type,
+                           gint       format,
+                           guchar    *data,
+                           gint       length);
+
+void       gdk_event_queue_append (GdkEvent *event);
+
+/* Please see gdkwindow.c for comments on how to use */ 
+HWND gdk_window_xid_at(HWND base, gint bx, gint by, gint x, gint y, GList *excludes, gboolean excl_child);
+HWND gdk_window_xid_at_coords(gint x, gint y, GList *excludes, gboolean excl_child);
+
+extern gint             gdk_debug_level;
+extern gint             gdk_show_events;
+extern gint             gdk_stack_trace;
+extern gchar           *gdk_display_name;
+extern HWND             gdk_root_window;
+extern HWND             gdk_leader_window;
+GDKVAR GdkWindowPrivate         gdk_root_parent;
+GDKVAR Atom             gdk_selection_property;
+extern GdkWindow       *selection_owner[];
+GDKVAR gchar           *gdk_progclass;
+GDKVAR gint             gdk_error_code;
+GDKVAR gint             gdk_error_warnings;
+GDKVAR gint              gdk_null_window_warnings;
+extern GList            *gdk_default_filters;
+
+#ifdef USE_XIM
+/* XIM support */
+gint   gdk_im_open              (void);
+void   gdk_im_close             (void);
+void   gdk_ic_cleanup           (void);
+
+extern GdkICPrivate *gdk_xim_ic;               /* currently using IC */
+extern GdkWindow *gdk_xim_window;              /* currently using Window */
+#endif /* USE_XIM */
+
+extern HDC              gdk_DC;
+extern HINSTANCE        gdk_DLLInstance;
+extern HINSTANCE        gdk_ProgInstance;
+
+extern UINT             gdk_selection_notify_msg;
+extern UINT             gdk_selection_request_msg;
+extern UINT             gdk_selection_clear_msg;
+extern GdkAtom          gdk_clipboard_atom;
+extern GdkAtom          gdk_win32_dropfiles_atom;
+extern GdkAtom          gdk_ole2_dnd_atom;
+
+/* Debugging support */
+
+#ifdef G_ENABLE_DEBUG
+
+#define GDK_NOTE(type,action)               G_STMT_START { \
+    if (gdk_debug_flags & GDK_DEBUG_##type)                \
+       { action; };                         } G_STMT_END
+
+#else /* !G_ENABLE_DEBUG */
+
+#define GDK_NOTE(type,action)
+      
+#endif /* G_ENABLE_DEBUG */
+
+extern guint gdk_debug_flags;
+
+/* Internal functions for debug output etc. */
+
+char   *gdk_color_to_string (GdkColor *);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GDK_PRIVATE_H__ */
diff --git a/gdk/win32/gdkprivate.h b/gdk/win32/gdkprivate.h
new file mode 100644 (file)
index 0000000..e90da96
--- /dev/null
@@ -0,0 +1,420 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GDK_PRIVATE_H__
+#define __GDK_PRIVATE_H__
+
+#define STRICT                 /* We want strict type checks */
+#include <windows.h>
+
+#include <time.h>
+#include <gdk/gdktypes.h>
+
+/* Define corresponding Windows types for some X11 types, just for laziness.
+ */
+
+#include <glib.h>
+
+typedef HANDLE XID;
+typedef PALETTEENTRY XColor;
+typedef HDC GC;
+typedef ATOM Atom;
+typedef HCURSOR Cursor;
+typedef guint VisualID;
+typedef DWORD KeySym;
+typedef int Status;
+
+/* Define some of the X11 constants also here, again just for laziness */
+
+/* Generic null resource */
+#define None 0
+
+/* Error codes */
+#define Success            0
+
+/* Grabbing status */
+#define GrabSuccess       0
+#define AlreadyGrabbed    2
+
+/* For CreateColormap */
+#define AllocNone 0
+#define AllocAll 1
+
+/* Notify modes */
+#define NotifyNormal 0
+#define NotifyHint 1
+
+/* Some structs are somewhat useful to emulate internally, just to
+   keep the code less #ifdefed.  */
+typedef struct {
+  HPALETTE palette;            /* Palette handle used when drawing. */
+  guint size;                  /* Number of entries in the palette. */
+  gboolean stale;              /* 1 if palette needs to be realized,
+                                * otherwise 0. */
+  gboolean *in_use;
+  gboolean rc_palette;         /* If RC_PALETTE is on in the RASTERCAPS */
+  gulong sizepalette;          /* SIZEPALETTE if rc_palette */
+} ColormapStruct, *Colormap;
+  
+typedef struct {
+  gint map_entries;
+  guint visualid;
+  guint bitspixel;
+} Visual;
+
+typedef struct {
+  Colormap colormap;
+  unsigned long red_max;
+  unsigned long red_mult;
+  unsigned long green_max;
+  unsigned long green_mult;
+  unsigned long blue_max;
+  unsigned long blue_mult;
+  unsigned long base_pixel;
+} XStandardColormap;
+
+extern LRESULT CALLBACK 
+gdk_WindowProc (HWND, UINT, WPARAM, LPARAM);
+
+#define gdk_window_lookup(xid)    ((GdkWindow*) gdk_xid_table_lookup (xid))
+#define gdk_pixmap_lookup(xid)    ((GdkPixmap*) gdk_xid_table_lookup (xid))
+
+/* HFONTs clash with HWNDs, so add dithering to HFONTs... (hack) */
+#define HFONT_DITHER 43
+#define gdk_font_lookup(xid)      ((GdkFont*) gdk_xid_table_lookup ((HANDLE) ((guint) xid + HFONT_DITHER)))
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+typedef struct _GdkWindowPrivate       GdkWindowPrivate;
+typedef struct _GdkWindowPrivate       GdkPixmapPrivate;
+typedef struct _GdkImagePrivate               GdkImagePrivate;
+typedef struct _GdkGCPrivate          GdkGCPrivate;
+typedef struct _GdkColormapPrivate     GdkColormapPrivate;
+typedef struct _GdkColorInfo           GdkColorInfo;
+typedef struct _GdkVisualPrivate       GdkVisualPrivate;
+typedef struct _GdkFontPrivate        GdkFontPrivate;
+typedef struct _GdkCursorPrivate       GdkCursorPrivate;
+typedef struct _GdkEventFilter        GdkEventFilter;
+typedef struct _GdkClientFilter               GdkClientFilter;
+typedef struct _GdkColorContextPrivate GdkColorContextPrivate;
+typedef struct _GdkRegionPrivate       GdkRegionPrivate;
+
+
+struct _GdkWindowPrivate
+{
+  GdkWindow window;
+  GdkWindow *parent;
+  HANDLE xwindow;
+  gint16 x;
+  gint16 y;
+  guint16 width;
+  guint16 height;
+  guint8 resize_count;
+  guint8 window_type;
+  guint ref_count;
+  guint destroyed : 2;
+  guint mapped : 1;
+  guint guffaw_gravity : 1;
+
+  /* We must keep the event mask here to filter them ourselves */
+  gint event_mask;
+
+  /* Values for bg_type */
+#define GDK_WIN32_BG_NORMAL 0
+#define GDK_WIN32_BG_PIXEL 1
+#define GDK_WIN32_BG_PIXMAP 2
+#define GDK_WIN32_BG_PARENT_RELATIVE 3
+#define GDK_WIN32_BG_TRANSPARENT 4
+
+  /* We draw the background ourselves at WM_ERASEBKGND  */
+  guchar bg_type;
+  GdkColor bg_pixel;
+  GdkPixmap *bg_pixmap;
+
+  HCURSOR xcursor;
+
+  /* Window size hints */
+  gint hint_flags;
+  gint hint_x, hint_y;
+  gint hint_min_width, hint_min_height;
+  gint hint_max_width, hint_max_height;
+
+  gint extension_events;
+  gboolean extension_events_selected;
+
+  GList *filters;
+  GdkColormap *colormap;
+  GList *children;
+};
+
+struct _GdkImagePrivate
+{
+  GdkImage image;
+  HBITMAP ximage;
+  gpointer x_shm_info;
+
+  void (*image_put) (GdkDrawable *window,
+                    GdkGC       *gc,
+                    GdkImage    *image,
+                    gint         xsrc,
+                    gint         ysrc,
+                    gint         xdest,
+                    gint         ydest,
+                    gint         width,
+                    gint         height);
+};
+
+struct _GdkGCPrivate
+{
+  GdkGC gc;
+  GC xgc;
+  /* A Windows Device Context (DC) is not equivalent to an X11
+   * GC. We can use a DC only in the window for which it was
+   * allocated, or (in the case of a memory DC) with the bitmap that
+   * has been selected into it. Thus, we have to release and
+   * reallocate a DC each time the GdkGC is used to paint into a new
+   * window or pixmap. We thus keep all the necessary values in the
+   * GdkGCPrivate struct.
+   */
+  GdkGCValuesMask values_mask;
+  GdkColor foreground;
+  GdkColor background;
+  HFONT font;
+  gint rop2;
+  GdkFill fill_style;
+  GdkPixmap *tile;
+  GdkPixmap *stipple;
+  HRGN clip_region;
+  GdkSubwindowMode subwindow_mode;
+  gint ts_x_origin;
+  gint ts_y_origin;
+  gint clip_x_origin;
+  gint clip_y_origin;
+  gint graphics_exposures;
+  gint pen_width;
+  DWORD pen_style;
+  HANDLE hwnd;                 /* If a DC is allocated, for which window
+                                  or what bitmap is selected into it */
+  int saved_dc;
+  guint ref_count;
+};
+
+typedef enum {
+  GDK_COLOR_WRITEABLE = 1 << 0
+} GdkColorInfoFlags;
+
+struct _GdkColorInfo
+{
+  GdkColorInfoFlags flags;
+  guint ref_count;
+};
+
+struct _GdkColormapPrivate
+{
+  GdkColormap colormap;
+  Colormap xcolormap;
+  GdkVisual *visual;
+  gint private_val;
+
+  GHashTable *hash;
+  GdkColorInfo *info;
+  time_t last_sync_time;
+  
+  guint ref_count;
+};
+
+struct _GdkVisualPrivate
+{
+  GdkVisual visual;
+  Visual *xvisual;
+};
+
+struct _GdkFontPrivate
+{
+  GdkFont font;
+  /* XFontStruct *xfont; */
+  /* generic pointer point to XFontStruct or XFontSet */
+  /* in Win32 a HFONT */ 
+  gpointer xfont;
+  guint ref_count;
+};
+
+struct _GdkCursorPrivate
+{
+  GdkCursor cursor;
+  Cursor xcursor;
+};
+
+struct _GdkEventFilter {
+  GdkFilterFunc function;
+  gpointer data;
+};
+
+struct _GdkClientFilter {
+  GdkAtom       type;
+  GdkFilterFunc function;
+  gpointer      data;
+};
+
+#ifdef USE_XIM
+
+typedef struct _GdkICPrivate GdkICPrivate;
+
+struct _GdkICPrivate
+{
+  XIC xic;
+  GdkICAttr *attr;
+  GdkICAttributesType mask;
+};
+
+#endif /* USE_XIM */
+
+struct _GdkColorContextPrivate
+{
+  GdkColorContext color_context;
+  XStandardColormap std_cmap;
+};
+
+struct _GdkRegionPrivate
+{
+  GdkRegion region;
+  HRGN xregion;
+};
+
+typedef enum {
+  GDK_DEBUG_MISC          = 1 << 0,
+  GDK_DEBUG_EVENTS        = 1 << 1,
+  GDK_DEBUG_DND           = 1 << 2,
+  GDK_DEBUG_COLOR_CONTEXT = 1 << 3,
+  GDK_DEBUG_XIM           = 1 << 4,
+  GDK_DEBUG_SELECTION    = 1 << 5
+} GdkDebugFlag;
+
+void gdk_events_init (void);
+void gdk_window_init (void);
+void gdk_visual_init (void);
+void gdk_selection_init (void);
+void gdk_dnd_init    (void);
+void gdk_dnd_exit    (void);
+void gdk_image_init  (void);
+void gdk_image_exit  (void);
+
+GdkColormap* gdk_colormap_lookup (Colormap  xcolormap);
+GdkVisual*   gdk_visual_lookup  (Visual   *xvisual);
+
+void gdk_window_add_colormap_windows (GdkWindow *window);
+void gdk_window_destroy_notify      (GdkWindow *window);
+
+void    gdk_xid_table_insert (XID      *xid,
+                              gpointer  data);
+void    gdk_xid_table_remove (XID       xid);
+gpointer gdk_xid_table_lookup (XID      xid);
+
+/* Internal functions */
+
+HDC    gdk_gc_predraw  (GdkWindowPrivate *window_private,
+                        GdkGCPrivate *gc_private);
+void   gdk_gc_postdraw (GdkWindowPrivate *window_private,
+                        GdkGCPrivate *gc_private);
+HRGN   BitmapToRegion  (HBITMAP hBmp);
+
+void    gdk_sel_prop_store (GdkWindow *owner,
+                           GdkAtom    type,
+                           gint       format,
+                           guchar    *data,
+                           gint       length);
+
+void       gdk_event_queue_append (GdkEvent *event);
+
+/* Please see gdkwindow.c for comments on how to use */ 
+HWND gdk_window_xid_at(HWND base, gint bx, gint by, gint x, gint y, GList *excludes, gboolean excl_child);
+HWND gdk_window_xid_at_coords(gint x, gint y, GList *excludes, gboolean excl_child);
+
+extern gint             gdk_debug_level;
+extern gint             gdk_show_events;
+extern gint             gdk_stack_trace;
+extern gchar           *gdk_display_name;
+extern HWND             gdk_root_window;
+extern HWND             gdk_leader_window;
+GDKVAR GdkWindowPrivate         gdk_root_parent;
+GDKVAR Atom             gdk_selection_property;
+extern GdkWindow       *selection_owner[];
+GDKVAR gchar           *gdk_progclass;
+GDKVAR gint             gdk_error_code;
+GDKVAR gint             gdk_error_warnings;
+GDKVAR gint              gdk_null_window_warnings;
+extern GList            *gdk_default_filters;
+
+#ifdef USE_XIM
+/* XIM support */
+gint   gdk_im_open              (void);
+void   gdk_im_close             (void);
+void   gdk_ic_cleanup           (void);
+
+extern GdkICPrivate *gdk_xim_ic;               /* currently using IC */
+extern GdkWindow *gdk_xim_window;              /* currently using Window */
+#endif /* USE_XIM */
+
+extern HDC              gdk_DC;
+extern HINSTANCE        gdk_DLLInstance;
+extern HINSTANCE        gdk_ProgInstance;
+
+extern UINT             gdk_selection_notify_msg;
+extern UINT             gdk_selection_request_msg;
+extern UINT             gdk_selection_clear_msg;
+extern GdkAtom          gdk_clipboard_atom;
+extern GdkAtom          gdk_win32_dropfiles_atom;
+extern GdkAtom          gdk_ole2_dnd_atom;
+
+/* Debugging support */
+
+#ifdef G_ENABLE_DEBUG
+
+#define GDK_NOTE(type,action)               G_STMT_START { \
+    if (gdk_debug_flags & GDK_DEBUG_##type)                \
+       { action; };                         } G_STMT_END
+
+#else /* !G_ENABLE_DEBUG */
+
+#define GDK_NOTE(type,action)
+      
+#endif /* G_ENABLE_DEBUG */
+
+extern guint gdk_debug_flags;
+
+/* Internal functions for debug output etc. */
+
+char   *gdk_color_to_string (GdkColor *);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GDK_PRIVATE_H__ */
diff --git a/gdk/win32/gdkproperty-win32.c b/gdk/win32/gdkproperty-win32.c
new file mode 100644 (file)
index 0000000..5cc68ec
--- /dev/null
@@ -0,0 +1,221 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include "gdk.h"
+#include "gdkprivate.h"
+
+GdkAtom
+gdk_atom_intern (const gchar *atom_name,
+                gint         only_if_exists)
+{
+  GdkAtom retval;
+  static GHashTable *atom_hash = NULL;
+  
+  if (!atom_hash)
+    atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+  retval = GPOINTER_TO_UINT (g_hash_table_lookup (atom_hash, atom_name));
+  if (!retval)
+    {
+      if (strcmp (atom_name, "PRIMARY") == 0)
+       retval = GDK_SELECTION_PRIMARY;
+      else if (strcmp (atom_name, "SECONDARY") == 0)
+       retval = GDK_SELECTION_SECONDARY;
+      else if (strcmp (atom_name, "ATOM") == 0)
+       retval = GDK_SELECTION_TYPE_ATOM;
+      else if (strcmp (atom_name, "BITMAP") == 0)
+       retval = GDK_SELECTION_TYPE_BITMAP;
+      else if (strcmp (atom_name, "COLORMAP") == 0)
+       retval = GDK_SELECTION_TYPE_COLORMAP;
+      else if (strcmp (atom_name, "DRAWABLE") == 0)
+       retval = GDK_SELECTION_TYPE_DRAWABLE;
+      else if (strcmp (atom_name, "INTEGER") == 0)
+       retval = GDK_SELECTION_TYPE_INTEGER;
+      else if (strcmp (atom_name, "PIXMAP") == 0)
+       retval = GDK_SELECTION_TYPE_PIXMAP;
+      else if (strcmp (atom_name, "WINDOW") == 0)
+       retval = GDK_SELECTION_TYPE_WINDOW;
+      else if (strcmp (atom_name, "STRING") == 0)
+       retval = GDK_SELECTION_TYPE_STRING;
+      else
+       {
+         retval = GlobalFindAtom (atom_name);
+         if (only_if_exists && retval == 0)
+           retval = 0;
+         else
+           retval = GlobalAddAtom (atom_name);
+       }
+      g_hash_table_insert (atom_hash, 
+                          g_strdup (atom_name), 
+                          GUINT_TO_POINTER (retval));
+    }
+
+  return retval;
+}
+
+gchar *
+gdk_atom_name (GdkAtom atom)
+{
+  gchar name[256];
+
+  switch (atom)
+    {
+    case GDK_SELECTION_PRIMARY: return g_strdup ("PRIMARY");
+    case GDK_SELECTION_SECONDARY: return g_strdup ("SECONDARY");
+    case GDK_SELECTION_TYPE_ATOM: return g_strdup ("ATOM");
+    case GDK_SELECTION_TYPE_BITMAP: return g_strdup ("BITMAP");
+    case GDK_SELECTION_TYPE_COLORMAP: return g_strdup ("COLORMAP");
+    case GDK_SELECTION_TYPE_DRAWABLE: return g_strdup ("DRAWABLE");
+    case GDK_SELECTION_TYPE_INTEGER: return g_strdup ("INTEGER");
+    case GDK_SELECTION_TYPE_PIXMAP: return g_strdup ("PIXMAP");
+    case GDK_SELECTION_TYPE_WINDOW: return g_strdup ("WINDOW");
+    case GDK_SELECTION_TYPE_STRING: return g_strdup ("STRING");
+    }
+  if (atom < 0xC000)
+    return g_strdup_printf ("#%x", atom);
+  else if (GlobalGetAtomName (atom, name, sizeof (name)) == 0)
+    return NULL;
+  return g_strdup (name);
+}
+
+gint
+gdk_property_get (GdkWindow   *window,
+                 GdkAtom      property,
+                 GdkAtom      type,
+                 gulong       offset,
+                 gulong       length,
+                 gint         pdelete,
+                 GdkAtom     *actual_property_type,
+                 gint        *actual_format_type,
+                 gint        *actual_length,
+                 guchar     **data)
+{
+  g_warning ("gdk_property_get: Not implemented");
+
+  return FALSE;
+}
+
+void
+gdk_property_change (GdkWindow   *window,
+                    GdkAtom      property,
+                    GdkAtom      type,
+                    gint         format,
+                    GdkPropMode  mode,
+                    guchar      *data,
+                    gint         nelements)
+{
+  GdkWindowPrivate *private;
+  HGLOBAL hdata;
+  gint i, length;
+  gchar *prop_name, *type_name;
+  guchar *ptr;
+
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return;
+
+  GDK_NOTE (SELECTION,
+           (prop_name = gdk_atom_name (property),
+            type_name = gdk_atom_name (type),
+            g_print ("gdk_property_change: %#x %#x (%s) %#x (%s) %s %d*%d bytes %.10s\n",
+                     private->xwindow, property, prop_name,
+                     type, type_name,
+                     (mode == GDK_PROP_MODE_REPLACE ? "REPLACE" :
+                      (mode == GDK_PROP_MODE_PREPEND ? "PREPEND" :
+                       (mode == GDK_PROP_MODE_APPEND ? "APPEND" :
+                        "???"))),
+                     format, nelements, data),
+            g_free (prop_name),
+            g_free (type_name)));
+
+  if (property == gdk_selection_property
+      && type == GDK_TARGET_STRING
+      && format == 8
+      && mode == GDK_PROP_MODE_REPLACE)
+    {
+      length = nelements;
+      ptr = data;
+      for (i = 0; i < nelements; i++)
+       if (*ptr++ == '\n')
+         length++;
+#if 1      
+      if (!OpenClipboard (private->xwindow))
+       {
+         g_warning ("gdk_property_change: OpenClipboard failed");
+         return;
+       }
+#endif
+      hdata = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE, length + 1);
+      ptr = GlobalLock (hdata);
+      GDK_NOTE (SELECTION, g_print ("...hdata=%#x, ptr=%#x\n", hdata, ptr));
+
+      for (i = 0; i < nelements; i++)
+       {
+         if (*data == '\n')
+           *ptr++ = '\r';
+         *ptr++ = *data++;
+       }
+      *ptr++ = '\0';
+      GlobalUnlock (hdata);
+      if (!SetClipboardData(CF_TEXT, hdata))
+       g_warning ("gdk_property_change: SetClipboardData failed: %d",
+                  GetLastError ());
+#if 1
+      if (!CloseClipboard ())
+       {
+         g_warning ("gdk_property_change: CloseClipboard failed");
+         return;
+       }
+#endif
+    }
+  else
+    g_warning ("gdk_property_change: General case not implemented");
+}
+
+void
+gdk_property_delete (GdkWindow *window,
+                    GdkAtom    property)
+{
+  GdkWindowPrivate *private;
+  gchar *prop_name, *type_name;
+  extern void gdk_selection_property_delete (GdkWindowPrivate *);
+
+  private = (GdkWindowPrivate*) window;
+
+  GDK_NOTE (SELECTION,
+           (prop_name = gdk_atom_name (property),
+            g_print ("gdk_property_delete: %#x %#x (%s)\n",
+                     (window ? private->xwindow : 0), property, prop_name),
+            g_free (prop_name)));
+
+  if (property == gdk_selection_property)
+    gdk_selection_property_delete (private);
+  else
+    g_warning ("gdk_property_delete: General case not implemented");
+}
diff --git a/gdk/win32/gdkproperty.c b/gdk/win32/gdkproperty.c
new file mode 100644 (file)
index 0000000..5cc68ec
--- /dev/null
@@ -0,0 +1,221 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include "gdk.h"
+#include "gdkprivate.h"
+
+GdkAtom
+gdk_atom_intern (const gchar *atom_name,
+                gint         only_if_exists)
+{
+  GdkAtom retval;
+  static GHashTable *atom_hash = NULL;
+  
+  if (!atom_hash)
+    atom_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+  retval = GPOINTER_TO_UINT (g_hash_table_lookup (atom_hash, atom_name));
+  if (!retval)
+    {
+      if (strcmp (atom_name, "PRIMARY") == 0)
+       retval = GDK_SELECTION_PRIMARY;
+      else if (strcmp (atom_name, "SECONDARY") == 0)
+       retval = GDK_SELECTION_SECONDARY;
+      else if (strcmp (atom_name, "ATOM") == 0)
+       retval = GDK_SELECTION_TYPE_ATOM;
+      else if (strcmp (atom_name, "BITMAP") == 0)
+       retval = GDK_SELECTION_TYPE_BITMAP;
+      else if (strcmp (atom_name, "COLORMAP") == 0)
+       retval = GDK_SELECTION_TYPE_COLORMAP;
+      else if (strcmp (atom_name, "DRAWABLE") == 0)
+       retval = GDK_SELECTION_TYPE_DRAWABLE;
+      else if (strcmp (atom_name, "INTEGER") == 0)
+       retval = GDK_SELECTION_TYPE_INTEGER;
+      else if (strcmp (atom_name, "PIXMAP") == 0)
+       retval = GDK_SELECTION_TYPE_PIXMAP;
+      else if (strcmp (atom_name, "WINDOW") == 0)
+       retval = GDK_SELECTION_TYPE_WINDOW;
+      else if (strcmp (atom_name, "STRING") == 0)
+       retval = GDK_SELECTION_TYPE_STRING;
+      else
+       {
+         retval = GlobalFindAtom (atom_name);
+         if (only_if_exists && retval == 0)
+           retval = 0;
+         else
+           retval = GlobalAddAtom (atom_name);
+       }
+      g_hash_table_insert (atom_hash, 
+                          g_strdup (atom_name), 
+                          GUINT_TO_POINTER (retval));
+    }
+
+  return retval;
+}
+
+gchar *
+gdk_atom_name (GdkAtom atom)
+{
+  gchar name[256];
+
+  switch (atom)
+    {
+    case GDK_SELECTION_PRIMARY: return g_strdup ("PRIMARY");
+    case GDK_SELECTION_SECONDARY: return g_strdup ("SECONDARY");
+    case GDK_SELECTION_TYPE_ATOM: return g_strdup ("ATOM");
+    case GDK_SELECTION_TYPE_BITMAP: return g_strdup ("BITMAP");
+    case GDK_SELECTION_TYPE_COLORMAP: return g_strdup ("COLORMAP");
+    case GDK_SELECTION_TYPE_DRAWABLE: return g_strdup ("DRAWABLE");
+    case GDK_SELECTION_TYPE_INTEGER: return g_strdup ("INTEGER");
+    case GDK_SELECTION_TYPE_PIXMAP: return g_strdup ("PIXMAP");
+    case GDK_SELECTION_TYPE_WINDOW: return g_strdup ("WINDOW");
+    case GDK_SELECTION_TYPE_STRING: return g_strdup ("STRING");
+    }
+  if (atom < 0xC000)
+    return g_strdup_printf ("#%x", atom);
+  else if (GlobalGetAtomName (atom, name, sizeof (name)) == 0)
+    return NULL;
+  return g_strdup (name);
+}
+
+gint
+gdk_property_get (GdkWindow   *window,
+                 GdkAtom      property,
+                 GdkAtom      type,
+                 gulong       offset,
+                 gulong       length,
+                 gint         pdelete,
+                 GdkAtom     *actual_property_type,
+                 gint        *actual_format_type,
+                 gint        *actual_length,
+                 guchar     **data)
+{
+  g_warning ("gdk_property_get: Not implemented");
+
+  return FALSE;
+}
+
+void
+gdk_property_change (GdkWindow   *window,
+                    GdkAtom      property,
+                    GdkAtom      type,
+                    gint         format,
+                    GdkPropMode  mode,
+                    guchar      *data,
+                    gint         nelements)
+{
+  GdkWindowPrivate *private;
+  HGLOBAL hdata;
+  gint i, length;
+  gchar *prop_name, *type_name;
+  guchar *ptr;
+
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return;
+
+  GDK_NOTE (SELECTION,
+           (prop_name = gdk_atom_name (property),
+            type_name = gdk_atom_name (type),
+            g_print ("gdk_property_change: %#x %#x (%s) %#x (%s) %s %d*%d bytes %.10s\n",
+                     private->xwindow, property, prop_name,
+                     type, type_name,
+                     (mode == GDK_PROP_MODE_REPLACE ? "REPLACE" :
+                      (mode == GDK_PROP_MODE_PREPEND ? "PREPEND" :
+                       (mode == GDK_PROP_MODE_APPEND ? "APPEND" :
+                        "???"))),
+                     format, nelements, data),
+            g_free (prop_name),
+            g_free (type_name)));
+
+  if (property == gdk_selection_property
+      && type == GDK_TARGET_STRING
+      && format == 8
+      && mode == GDK_PROP_MODE_REPLACE)
+    {
+      length = nelements;
+      ptr = data;
+      for (i = 0; i < nelements; i++)
+       if (*ptr++ == '\n')
+         length++;
+#if 1      
+      if (!OpenClipboard (private->xwindow))
+       {
+         g_warning ("gdk_property_change: OpenClipboard failed");
+         return;
+       }
+#endif
+      hdata = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE, length + 1);
+      ptr = GlobalLock (hdata);
+      GDK_NOTE (SELECTION, g_print ("...hdata=%#x, ptr=%#x\n", hdata, ptr));
+
+      for (i = 0; i < nelements; i++)
+       {
+         if (*data == '\n')
+           *ptr++ = '\r';
+         *ptr++ = *data++;
+       }
+      *ptr++ = '\0';
+      GlobalUnlock (hdata);
+      if (!SetClipboardData(CF_TEXT, hdata))
+       g_warning ("gdk_property_change: SetClipboardData failed: %d",
+                  GetLastError ());
+#if 1
+      if (!CloseClipboard ())
+       {
+         g_warning ("gdk_property_change: CloseClipboard failed");
+         return;
+       }
+#endif
+    }
+  else
+    g_warning ("gdk_property_change: General case not implemented");
+}
+
+void
+gdk_property_delete (GdkWindow *window,
+                    GdkAtom    property)
+{
+  GdkWindowPrivate *private;
+  gchar *prop_name, *type_name;
+  extern void gdk_selection_property_delete (GdkWindowPrivate *);
+
+  private = (GdkWindowPrivate*) window;
+
+  GDK_NOTE (SELECTION,
+           (prop_name = gdk_atom_name (property),
+            g_print ("gdk_property_delete: %#x %#x (%s)\n",
+                     (window ? private->xwindow : 0), property, prop_name),
+            g_free (prop_name)));
+
+  if (property == gdk_selection_property)
+    gdk_selection_property_delete (private);
+  else
+    g_warning ("gdk_property_delete: General case not implemented");
+}
diff --git a/gdk/win32/gdkrectangle.c b/gdk/win32/gdkrectangle.c
new file mode 100644 (file)
index 0000000..8fd435a
--- /dev/null
@@ -0,0 +1,108 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "gdk.h"
+
+
+
+void
+gdk_rectangle_union (GdkRectangle *src1,
+                    GdkRectangle *src2,
+                    GdkRectangle *dest)
+{
+  g_return_if_fail (src1 != NULL);
+  g_return_if_fail (src2 != NULL);
+  g_return_if_fail (dest != NULL);
+
+  dest->x = MIN (src1->x, src2->x);
+  dest->y = MIN (src1->y, src2->y);
+  dest->width = MAX (src1->x + src1->width, src2->x + src2->width) - dest->x;
+  dest->height = MAX (src1->y + src1->height, src2->y + src2->height) - dest->y;
+}
+
+gint
+gdk_rectangle_intersect (GdkRectangle *src1,
+                        GdkRectangle *src2,
+                        GdkRectangle *dest)
+{
+  GdkRectangle *temp;
+  gint src1_x2, src1_y2;
+  gint src2_x2, src2_y2;
+  gint return_val;
+
+  g_return_val_if_fail (src1 != NULL, FALSE);
+  g_return_val_if_fail (src2 != NULL, FALSE);
+  g_return_val_if_fail (dest != NULL, FALSE);
+
+  return_val = FALSE;
+
+  if (src2->x < src1->x)
+    {
+      temp = src1;
+      src1 = src2;
+      src2 = temp;
+    }
+  dest->x = src2->x;
+
+  src1_x2 = src1->x + src1->width;
+  src2_x2 = src2->x + src2->width;
+
+  if (src2->x < src1_x2)
+    {
+      if (src1_x2 < src2_x2)
+       dest->width = src1_x2 - dest->x;
+      else
+       dest->width = src2_x2 - dest->x;
+
+      if (src2->y < src1->y)
+       {
+         temp = src1;
+         src1 = src2;
+         src2 = temp;
+       }
+      dest->y = src2->y;
+
+      src1_y2 = src1->y + src1->height;
+      src2_y2 = src2->y + src2->height;
+
+      if (src2->y < src1_y2)
+       {
+         return_val = TRUE;
+
+         if (src1_y2 < src2_y2)
+           dest->height = src1_y2 - dest->y;
+         else
+           dest->height = src2_y2 - dest->y;
+
+         if (dest->height == 0)
+           return_val = FALSE;
+         if (dest->width == 0)
+           return_val = FALSE;
+       }
+    }
+
+  return return_val;
+}
diff --git a/gdk/win32/gdkregion-win32.c b/gdk/win32/gdkregion-win32.c
new file mode 100644 (file)
index 0000000..4a37c3b
--- /dev/null
@@ -0,0 +1,350 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdk.h"
+#include "gdkprivate.h"
+
+
+GdkRegion*
+gdk_region_new (void)
+{
+  GdkRegionPrivate *private;
+  GdkRegion *region;
+  HRGN xregion;
+
+  /* Create an empty region */
+  xregion = CreateRectRgn (1, 1, 0, 0);
+  private = g_new (GdkRegionPrivate, 1);
+  private->xregion = xregion;
+  region = (GdkRegion*) private;
+  region->user_data = NULL;
+
+  return region;
+}
+
+void
+gdk_region_destroy (GdkRegion *region)
+{
+  GdkRegionPrivate *private;
+
+  g_return_if_fail (region != NULL);
+
+  private = (GdkRegionPrivate *) region;
+  DeleteObject (private->xregion);
+  g_free (private);
+}
+
+gboolean
+gdk_region_empty (GdkRegion      *region)
+{
+  GdkRegionPrivate *private;
+  RECT rect;
+
+  g_return_val_if_fail (region != NULL, 0);
+
+  private = (GdkRegionPrivate *) region;
+  
+  return (GetRgnBox (private->xregion, &rect) == NULLREGION);
+}
+
+gboolean
+gdk_region_equal (GdkRegion      *region1,
+                  GdkRegion      *region2)
+{
+  GdkRegionPrivate *private1;
+  GdkRegionPrivate *private2;
+
+  g_return_val_if_fail (region1 != NULL, 0);
+  g_return_val_if_fail (region2 != NULL, 0);
+
+  private1 = (GdkRegionPrivate *) region1;
+  private2 = (GdkRegionPrivate *) region2;
+  
+  return EqualRgn (private1->xregion, private2->xregion);
+}
+
+void
+gdk_region_get_clipbox(GdkRegion    *region,
+                      GdkRectangle *rectangle)
+{
+  GdkRegionPrivate *rp;
+  RECT r;
+  
+  g_return_if_fail(region != NULL);
+  g_return_if_fail(rectangle != NULL);
+
+  rp = (GdkRegionPrivate *)region;
+    
+  GetRgnBox (rp->xregion, &r);
+  rectangle->x = r.left;
+  rectangle->y = r.top;
+  rectangle->width = r.right - r.left;
+  rectangle->height = r.bottom - r.top;
+}
+
+gboolean
+gdk_region_point_in (GdkRegion      *region,
+                     gint           x,
+                    gint           y)
+{
+  GdkRegionPrivate *private;
+
+  g_return_val_if_fail (region != NULL, 0);
+
+  private = (GdkRegionPrivate *) region;
+  
+  return PtInRegion (private->xregion, x, y);
+}
+
+GdkOverlapType
+gdk_region_rect_in (GdkRegion      *region,
+                    GdkRectangle   *rect)
+{
+  GdkRegionPrivate *private;
+  RECT r;
+  int res;
+
+  g_return_val_if_fail (region != NULL, 0);
+
+  private = (GdkRegionPrivate *) region;
+  
+  r.left = rect->x;
+  r.top = rect->y;
+  r.right = rect->x + rect->width;
+  r.bottom = rect->y + rect->height;
+  
+  if (RectInRegion (private->xregion, &r))
+    return GDK_OVERLAP_RECTANGLE_PART;
+
+  return GDK_OVERLAP_RECTANGLE_OUT;  /*what else ? */
+}
+                                   
+GdkRegion *
+gdk_region_polygon (GdkPoint    *points,
+                   gint         npoints,
+                   GdkFillRule  fill_rule)
+{
+  GdkRegionPrivate *private;
+  GdkRegion *region;
+  HRGN xregion;
+  POINT *pts;
+  gint xfill_rule = ALTERNATE;
+  gint i;
+
+  g_return_val_if_fail (points != NULL, NULL);
+  g_return_val_if_fail (npoints != 0, NULL); /* maybe we should check for at least three points */
+
+  switch (fill_rule)
+    {
+    case GDK_EVEN_ODD_RULE:
+      xfill_rule = ALTERNATE;
+      break;
+
+    case GDK_WINDING_RULE:
+      xfill_rule = WINDING;
+      break;
+    }
+
+  pts = g_malloc (npoints * sizeof (*pts));
+  for (i = 0; i < npoints; i++)
+    {
+      pts[i].x = points[i].x;
+      pts[i].y = points[i].y;
+    }
+  xregion = CreatePolygonRgn (pts, npoints, xfill_rule);
+  g_free (pts);
+
+  private = g_new (GdkRegionPrivate, 1);
+  private->xregion = xregion;
+  region = (GdkRegion *) private;
+  region->user_data = NULL;
+
+  return region;
+}
+
+void          
+gdk_region_offset (GdkRegion      *region,
+                   gint           dx,
+                  gint           dy)
+{
+  GdkRegionPrivate *private;
+
+  g_return_if_fail (region != NULL);
+
+  private = (GdkRegionPrivate *) region;
+  
+  OffsetRgn (private->xregion, dx, dy);
+}
+
+void
+gdk_region_shrink (GdkRegion      *region,
+                   gint           dx,
+                  gint           dy)
+{
+  GdkRegionPrivate *private;
+  RECT r;
+
+  g_return_if_fail (region != NULL);
+
+  private = (GdkRegionPrivate *) region;
+  
+  /* Is it correct just to intersect it with a smaller bounding box? */
+  GetRgnBox (private->xregion, &r);
+
+  if (-dx > r.right - r.left)
+    {
+      r.left += dx/2;
+      r.right -= dx/2;
+    }
+  if (-dy > r.bottom - r.top)
+    {
+      r.top += dy/2;
+      r.bottom -= dy/2;
+    }
+  
+  CombineRgn (private->xregion, private->xregion,
+             CreateRectRgnIndirect (&r), RGN_AND);
+}
+
+GdkRegion*    
+gdk_region_union_with_rect (GdkRegion      *region,
+                            GdkRectangle   *rect)
+{
+  GdkRegionPrivate *private;
+  GdkRegion *res;
+  GdkRegionPrivate *res_private;
+  RECT xrect;
+
+  g_return_val_if_fail (region != NULL, NULL);
+
+  private = (GdkRegionPrivate *) region;
+  
+  xrect.left = rect->x;
+  xrect.top = rect->y;
+  xrect.right = rect->x + rect->width;
+  xrect.bottom = rect->y + rect->height;
+
+  res = gdk_region_new ();
+  res_private = (GdkRegionPrivate *) res;
+  
+  CombineRgn (res_private->xregion, private->xregion,
+             CreateRectRgnIndirect (&xrect), RGN_OR);
+  return res;
+}
+
+GdkRegion*    
+gdk_regions_intersect (GdkRegion      *source1,
+                       GdkRegion      *source2)
+{
+  GdkRegionPrivate *private1;
+  GdkRegionPrivate *private2;
+  GdkRegion *res;
+  GdkRegionPrivate *res_private;
+
+  g_return_val_if_fail (source1 != NULL, NULL);
+  g_return_val_if_fail (source2 != NULL, NULL);
+
+  private1 = (GdkRegionPrivate *) source1;
+  private2 = (GdkRegionPrivate *) source2;
+
+  res = gdk_region_new ();
+  res_private = (GdkRegionPrivate *) res;
+  
+  CombineRgn (res_private->xregion, private1->xregion, private2->xregion,
+             RGN_AND);
+  return res;
+}
+
+GdkRegion* 
+gdk_regions_union (GdkRegion      *source1,
+                   GdkRegion      *source2)
+{
+  GdkRegionPrivate *private1;
+  GdkRegionPrivate *private2;
+  GdkRegion *res;
+  GdkRegionPrivate *res_private;
+
+  g_return_val_if_fail (source1 != NULL, NULL);
+  g_return_val_if_fail (source2 != NULL, NULL);
+
+  private1 = (GdkRegionPrivate *) source1;
+  private2 = (GdkRegionPrivate *) source2;
+
+  res = gdk_region_new ();
+  res_private = (GdkRegionPrivate *) res;
+  
+  CombineRgn (res_private->xregion, private1->xregion, private2->xregion,
+             RGN_OR);
+  return res;
+}
+
+GdkRegion*    
+gdk_regions_subtract (GdkRegion      *source1,
+                      GdkRegion      *source2)
+{
+  GdkRegionPrivate *private1;
+  GdkRegionPrivate *private2;
+  GdkRegion *res;
+  GdkRegionPrivate *res_private;
+
+  g_return_val_if_fail (source1 != NULL, NULL);
+  g_return_val_if_fail (source2 != NULL, NULL);
+
+  private1 = (GdkRegionPrivate *) source1;
+  private2 = (GdkRegionPrivate *) source2;
+
+  res = gdk_region_new ();
+  res_private = (GdkRegionPrivate *) res;
+  
+  CombineRgn (res_private->xregion, private1->xregion, private2->xregion,
+             RGN_DIFF);
+  return res;
+}
+
+GdkRegion*    
+gdk_regions_xor (GdkRegion      *source1,
+                 GdkRegion      *source2)
+{
+  GdkRegionPrivate *private1;
+  GdkRegionPrivate *private2;
+  GdkRegion *res;
+  GdkRegionPrivate *res_private;
+
+  g_return_val_if_fail (source1 != NULL, NULL);
+  g_return_val_if_fail (source2 != NULL, NULL);
+
+  private1 = (GdkRegionPrivate *) source1;
+  private2 = (GdkRegionPrivate *) source2;
+
+  res = gdk_region_new ();
+  res_private = (GdkRegionPrivate *) res;
+  
+  CombineRgn (res_private->xregion, private1->xregion, private2->xregion,
+             RGN_XOR);
+  return res;
+}
diff --git a/gdk/win32/gdkregion.c b/gdk/win32/gdkregion.c
new file mode 100644 (file)
index 0000000..4a37c3b
--- /dev/null
@@ -0,0 +1,350 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdk.h"
+#include "gdkprivate.h"
+
+
+GdkRegion*
+gdk_region_new (void)
+{
+  GdkRegionPrivate *private;
+  GdkRegion *region;
+  HRGN xregion;
+
+  /* Create an empty region */
+  xregion = CreateRectRgn (1, 1, 0, 0);
+  private = g_new (GdkRegionPrivate, 1);
+  private->xregion = xregion;
+  region = (GdkRegion*) private;
+  region->user_data = NULL;
+
+  return region;
+}
+
+void
+gdk_region_destroy (GdkRegion *region)
+{
+  GdkRegionPrivate *private;
+
+  g_return_if_fail (region != NULL);
+
+  private = (GdkRegionPrivate *) region;
+  DeleteObject (private->xregion);
+  g_free (private);
+}
+
+gboolean
+gdk_region_empty (GdkRegion      *region)
+{
+  GdkRegionPrivate *private;
+  RECT rect;
+
+  g_return_val_if_fail (region != NULL, 0);
+
+  private = (GdkRegionPrivate *) region;
+  
+  return (GetRgnBox (private->xregion, &rect) == NULLREGION);
+}
+
+gboolean
+gdk_region_equal (GdkRegion      *region1,
+                  GdkRegion      *region2)
+{
+  GdkRegionPrivate *private1;
+  GdkRegionPrivate *private2;
+
+  g_return_val_if_fail (region1 != NULL, 0);
+  g_return_val_if_fail (region2 != NULL, 0);
+
+  private1 = (GdkRegionPrivate *) region1;
+  private2 = (GdkRegionPrivate *) region2;
+  
+  return EqualRgn (private1->xregion, private2->xregion);
+}
+
+void
+gdk_region_get_clipbox(GdkRegion    *region,
+                      GdkRectangle *rectangle)
+{
+  GdkRegionPrivate *rp;
+  RECT r;
+  
+  g_return_if_fail(region != NULL);
+  g_return_if_fail(rectangle != NULL);
+
+  rp = (GdkRegionPrivate *)region;
+    
+  GetRgnBox (rp->xregion, &r);
+  rectangle->x = r.left;
+  rectangle->y = r.top;
+  rectangle->width = r.right - r.left;
+  rectangle->height = r.bottom - r.top;
+}
+
+gboolean
+gdk_region_point_in (GdkRegion      *region,
+                     gint           x,
+                    gint           y)
+{
+  GdkRegionPrivate *private;
+
+  g_return_val_if_fail (region != NULL, 0);
+
+  private = (GdkRegionPrivate *) region;
+  
+  return PtInRegion (private->xregion, x, y);
+}
+
+GdkOverlapType
+gdk_region_rect_in (GdkRegion      *region,
+                    GdkRectangle   *rect)
+{
+  GdkRegionPrivate *private;
+  RECT r;
+  int res;
+
+  g_return_val_if_fail (region != NULL, 0);
+
+  private = (GdkRegionPrivate *) region;
+  
+  r.left = rect->x;
+  r.top = rect->y;
+  r.right = rect->x + rect->width;
+  r.bottom = rect->y + rect->height;
+  
+  if (RectInRegion (private->xregion, &r))
+    return GDK_OVERLAP_RECTANGLE_PART;
+
+  return GDK_OVERLAP_RECTANGLE_OUT;  /*what else ? */
+}
+                                   
+GdkRegion *
+gdk_region_polygon (GdkPoint    *points,
+                   gint         npoints,
+                   GdkFillRule  fill_rule)
+{
+  GdkRegionPrivate *private;
+  GdkRegion *region;
+  HRGN xregion;
+  POINT *pts;
+  gint xfill_rule = ALTERNATE;
+  gint i;
+
+  g_return_val_if_fail (points != NULL, NULL);
+  g_return_val_if_fail (npoints != 0, NULL); /* maybe we should check for at least three points */
+
+  switch (fill_rule)
+    {
+    case GDK_EVEN_ODD_RULE:
+      xfill_rule = ALTERNATE;
+      break;
+
+    case GDK_WINDING_RULE:
+      xfill_rule = WINDING;
+      break;
+    }
+
+  pts = g_malloc (npoints * sizeof (*pts));
+  for (i = 0; i < npoints; i++)
+    {
+      pts[i].x = points[i].x;
+      pts[i].y = points[i].y;
+    }
+  xregion = CreatePolygonRgn (pts, npoints, xfill_rule);
+  g_free (pts);
+
+  private = g_new (GdkRegionPrivate, 1);
+  private->xregion = xregion;
+  region = (GdkRegion *) private;
+  region->user_data = NULL;
+
+  return region;
+}
+
+void          
+gdk_region_offset (GdkRegion      *region,
+                   gint           dx,
+                  gint           dy)
+{
+  GdkRegionPrivate *private;
+
+  g_return_if_fail (region != NULL);
+
+  private = (GdkRegionPrivate *) region;
+  
+  OffsetRgn (private->xregion, dx, dy);
+}
+
+void
+gdk_region_shrink (GdkRegion      *region,
+                   gint           dx,
+                  gint           dy)
+{
+  GdkRegionPrivate *private;
+  RECT r;
+
+  g_return_if_fail (region != NULL);
+
+  private = (GdkRegionPrivate *) region;
+  
+  /* Is it correct just to intersect it with a smaller bounding box? */
+  GetRgnBox (private->xregion, &r);
+
+  if (-dx > r.right - r.left)
+    {
+      r.left += dx/2;
+      r.right -= dx/2;
+    }
+  if (-dy > r.bottom - r.top)
+    {
+      r.top += dy/2;
+      r.bottom -= dy/2;
+    }
+  
+  CombineRgn (private->xregion, private->xregion,
+             CreateRectRgnIndirect (&r), RGN_AND);
+}
+
+GdkRegion*    
+gdk_region_union_with_rect (GdkRegion      *region,
+                            GdkRectangle   *rect)
+{
+  GdkRegionPrivate *private;
+  GdkRegion *res;
+  GdkRegionPrivate *res_private;
+  RECT xrect;
+
+  g_return_val_if_fail (region != NULL, NULL);
+
+  private = (GdkRegionPrivate *) region;
+  
+  xrect.left = rect->x;
+  xrect.top = rect->y;
+  xrect.right = rect->x + rect->width;
+  xrect.bottom = rect->y + rect->height;
+
+  res = gdk_region_new ();
+  res_private = (GdkRegionPrivate *) res;
+  
+  CombineRgn (res_private->xregion, private->xregion,
+             CreateRectRgnIndirect (&xrect), RGN_OR);
+  return res;
+}
+
+GdkRegion*    
+gdk_regions_intersect (GdkRegion      *source1,
+                       GdkRegion      *source2)
+{
+  GdkRegionPrivate *private1;
+  GdkRegionPrivate *private2;
+  GdkRegion *res;
+  GdkRegionPrivate *res_private;
+
+  g_return_val_if_fail (source1 != NULL, NULL);
+  g_return_val_if_fail (source2 != NULL, NULL);
+
+  private1 = (GdkRegionPrivate *) source1;
+  private2 = (GdkRegionPrivate *) source2;
+
+  res = gdk_region_new ();
+  res_private = (GdkRegionPrivate *) res;
+  
+  CombineRgn (res_private->xregion, private1->xregion, private2->xregion,
+             RGN_AND);
+  return res;
+}
+
+GdkRegion* 
+gdk_regions_union (GdkRegion      *source1,
+                   GdkRegion      *source2)
+{
+  GdkRegionPrivate *private1;
+  GdkRegionPrivate *private2;
+  GdkRegion *res;
+  GdkRegionPrivate *res_private;
+
+  g_return_val_if_fail (source1 != NULL, NULL);
+  g_return_val_if_fail (source2 != NULL, NULL);
+
+  private1 = (GdkRegionPrivate *) source1;
+  private2 = (GdkRegionPrivate *) source2;
+
+  res = gdk_region_new ();
+  res_private = (GdkRegionPrivate *) res;
+  
+  CombineRgn (res_private->xregion, private1->xregion, private2->xregion,
+             RGN_OR);
+  return res;
+}
+
+GdkRegion*    
+gdk_regions_subtract (GdkRegion      *source1,
+                      GdkRegion      *source2)
+{
+  GdkRegionPrivate *private1;
+  GdkRegionPrivate *private2;
+  GdkRegion *res;
+  GdkRegionPrivate *res_private;
+
+  g_return_val_if_fail (source1 != NULL, NULL);
+  g_return_val_if_fail (source2 != NULL, NULL);
+
+  private1 = (GdkRegionPrivate *) source1;
+  private2 = (GdkRegionPrivate *) source2;
+
+  res = gdk_region_new ();
+  res_private = (GdkRegionPrivate *) res;
+  
+  CombineRgn (res_private->xregion, private1->xregion, private2->xregion,
+             RGN_DIFF);
+  return res;
+}
+
+GdkRegion*    
+gdk_regions_xor (GdkRegion      *source1,
+                 GdkRegion      *source2)
+{
+  GdkRegionPrivate *private1;
+  GdkRegionPrivate *private2;
+  GdkRegion *res;
+  GdkRegionPrivate *res_private;
+
+  g_return_val_if_fail (source1 != NULL, NULL);
+  g_return_val_if_fail (source2 != NULL, NULL);
+
+  private1 = (GdkRegionPrivate *) source1;
+  private2 = (GdkRegionPrivate *) source2;
+
+  res = gdk_region_new ();
+  res_private = (GdkRegionPrivate *) res;
+  
+  CombineRgn (res_private->xregion, private1->xregion, private2->xregion,
+             RGN_XOR);
+  return res;
+}
diff --git a/gdk/win32/gdkrgb.c b/gdk/win32/gdkrgb.c
new file mode 100644 (file)
index 0000000..feb5ce5
--- /dev/null
@@ -0,0 +1,3205 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* For more information on GdkRgb, see http://www.levien.com/gdkrgb/
+
+   Raph Levien <raph@acm.org>
+   */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include <math.h>
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#  if STDC_HEADERS
+#    include <stdio.h>
+#    include <stdlib.h>
+#    include <string.h>
+#  endif
+#else
+#  include <stdio.h>
+#  include <stdlib.h>
+#endif
+
+
+#define ENABLE_GRAYSCALE
+
+#include "config.h"
+#ifdef GDK_RGB_STANDALONE
+
+/* Compiling as a standalone module (i.e. with Gtk 1.0) */
+/* gtk/gtk.h is already included in gdkrgbstub.c */
+#include "config.h"
+#include <gdk/gdkprivate.h>
+
+#else
+
+/* Compiling as a part of Gtk 1.1 or later */
+#include "../config.h"
+#include "gdk.h"
+#include "gdkprivate.h"
+
+#endif
+
+#include "gdkrgb.h"
+
+typedef struct _GdkRgbInfo   GdkRgbInfo;
+
+typedef void (*GdkRgbConvFunc) (GdkImage *image,
+                               gint x0, gint y0,
+                               gint width, gint height,
+                               guchar *buf, int rowstride,
+                               gint x_align, gint y_align,
+                               GdkRgbCmap *cmap);
+
+/* Some of these fields should go, as they're not being used at all.
+   Globals should generally migrate into here - it's very likely that
+   we'll want to run more than one GdkRgbInfo context at the same time
+   (i.e. some but not all windows have privately installed
+   colormaps). */
+
+struct _GdkRgbInfo
+{
+  GdkVisual *visual;
+  GdkColormap *cmap;
+
+  gulong *color_pixels;
+  gulong *gray_pixels;
+  gulong *reserved_pixels;
+
+  guint nred_shades;
+  guint ngreen_shades;
+  guint nblue_shades;
+  guint ngray_shades;
+  guint nreserved;
+
+  guint bpp;
+  gint cmap_alloced;
+  gdouble gamma;
+
+  /* Generally, the stage buffer is used to convert 32bit RGB, gray,
+     and indexed images into 24 bit packed RGB. */
+  guchar *stage_buf;
+
+  GdkRgbCmap *gray_cmap;
+
+  gboolean dith_default;
+
+  gboolean bitmap; /* set true if in 1 bit per pixel mode */
+  GdkGC *own_gc;
+
+  /* Convert functions */
+  GdkRgbConvFunc conv;
+  GdkRgbConvFunc conv_d;
+
+  GdkRgbConvFunc conv_32;
+  GdkRgbConvFunc conv_32_d;
+
+  GdkRgbConvFunc conv_gray;
+  GdkRgbConvFunc conv_gray_d;
+
+  GdkRgbConvFunc conv_indexed;
+  GdkRgbConvFunc conv_indexed_d;
+};
+
+static gboolean gdk_rgb_install_cmap = FALSE;
+static gint gdk_rgb_min_colors = 5 * 5 * 5;
+static gboolean gdk_rgb_verbose = FALSE;
+
+#define IMAGE_WIDTH 256
+#define STAGE_ROWSTRIDE (IMAGE_WIDTH * 3)
+#define IMAGE_HEIGHT 64
+#define N_IMAGES 6
+
+static GdkRgbInfo *image_info = NULL;
+static GdkImage *static_image[N_IMAGES];
+static gint static_image_idx;
+
+static guchar *colorcube;
+static guchar *colorcube_d;
+
+static gint
+gdk_rgb_cmap_fail (const char *msg, GdkColormap *cmap, gulong *pixels)
+{
+  gulong free_pixels[256];
+  gint n_free;
+  gint i;
+
+#ifdef VERBOSE
+  g_print ("%s", msg);
+#endif
+  n_free = 0;
+  for (i = 0; i < 256; i++)
+    if (pixels[i] < 256)
+      free_pixels[n_free++] = pixels[i];
+  if (n_free)
+    gdk_colors_free (cmap, free_pixels, n_free, 0);
+  return 0;
+}
+
+static void
+gdk_rgb_make_colorcube (gulong *pixels, gint nr, gint ng, gint nb)
+{
+  guchar rt[16], gt[16], bt[16];
+  gint i;
+
+  colorcube = g_new (guchar, 4096);
+  for (i = 0; i < 16; i++)
+    {
+      rt[i] = ng * nb * ((i * 17 * (nr - 1) + 128) >> 8);
+      gt[i] = nb * ((i * 17 * (ng - 1) + 128) >> 8);
+      bt[i] = ((i * 17 * (nb - 1) + 128) >> 8);
+    }
+
+  for (i = 0; i < 4096; i++)
+    {
+      colorcube[i] = pixels[rt[i >> 8] + gt[(i >> 4) & 0x0f] + bt[i & 0x0f]];
+#ifdef VERBOSE
+      g_print ("%03x %02x %x %x %x\n", i, colorcube[i], rt[i >> 8], gt[(i >> 4) & 0x0f], bt[i & 0x0f]);
+#endif
+    }
+}
+
+/* this is the colorcube suitable for dithering */
+static void
+gdk_rgb_make_colorcube_d (gulong *pixels, gint nr, gint ng, gint nb)
+{
+  gint r, g, b;
+  gint i;
+
+  colorcube_d = g_new (guchar, 512);
+  for (i = 0; i < 512; i++)
+    {
+      r = MIN (nr - 1, i >> 6);
+      g = MIN (ng - 1, (i >> 3) & 7);
+      b = MIN (nb - 1, i & 7);
+      colorcube_d[i] = pixels[(r * ng + g) * nb + b];
+    }
+}
+
+/* Try installing a color cube of the specified size.
+   Make the colorcube and return TRUE on success */
+static gint
+gdk_rgb_try_colormap (gint nr, gint ng, gint nb)
+{
+  gint r, g, b;
+  gint ri, gi, bi;
+  gint r0, g0, b0;
+  GdkColormap *cmap;
+  GdkColor color;
+  gulong pixels[256];
+  gulong junk[256];
+  gint i;
+  gint d2;
+  gint colors_needed;
+  gint idx;
+  gint best[256];
+
+  if (nr * ng * nb < gdk_rgb_min_colors)
+    return FALSE;
+
+  if (image_info->cmap_alloced)
+    cmap = image_info->cmap;
+  else
+    cmap = gdk_colormap_get_system ();
+
+  colors_needed = nr * ng * nb;
+  for (i = 0; i < 256; i++)
+    {
+      best[i] = 192;
+      pixels[i] = 256;
+    }
+
+#ifndef GAMMA
+  if (!gdk_rgb_install_cmap)
+  /* find color cube colors that are already present */
+  for (i = 0; i < MIN (256, cmap->size); i++)
+    {
+      r = cmap->colors[i].red >> 8;
+      g = cmap->colors[i].green >> 8;
+      b = cmap->colors[i].blue >> 8;
+      ri = (r * (nr - 1) + 128) >> 8;
+      gi = (g * (ng - 1) + 128) >> 8;
+      bi = (b * (nb - 1) + 128) >> 8;
+      r0 = ri * 255 / (nr - 1);
+      g0 = gi * 255 / (ng - 1);
+      b0 = bi * 255 / (nb - 1);
+      idx = ((ri * nr) + gi) * nb + bi;
+      d2 = (r - r0) * (r - r0) + (g - g0) * (g - g0) + (b - b0) * (b - b0);
+      if (d2 < best[idx]) {
+       if (pixels[idx] < 256)
+         gdk_colors_free (cmap, pixels + idx, 1, 0);
+       else
+         colors_needed--;
+       color = cmap->colors[i];
+       if (!gdk_color_alloc (cmap, &color))
+         return gdk_rgb_cmap_fail ("error allocating system color\n",
+                                   cmap, pixels);
+       pixels[idx] = color.pixel; /* which is almost certainly i */
+       best[idx] = d2;
+      }
+    }
+#endif
+
+  if (colors_needed)
+    {
+      if (!gdk_colors_alloc (cmap, 0, NULL, 0, junk, colors_needed))
+       {
+         char tmp_str[80];
+         
+         sprintf (tmp_str,
+                  "%d %d %d colormap failed (in gdk_colors_alloc)\n",
+                  nr, ng, nb);
+         return gdk_rgb_cmap_fail (tmp_str, cmap, pixels);
+       }
+
+      gdk_colors_free (cmap, junk, colors_needed, 0);
+    }
+
+  for (r = 0, i = 0; r < nr; r++)
+    for (g = 0; g < ng; g++)
+      for (b = 0; b < nb; b++, i++)
+       {
+         if (pixels[i] == 256)
+           {
+             color.red = r * 65535 / (nr - 1);
+             color.green = g * 65535 / (ng - 1);
+             color.blue = b * 65535 / (nb - 1);
+
+#ifdef GAMMA
+             color.red = 65535 * pow (color.red / 65535.0, 0.5);
+             color.green = 65535 * pow (color.green / 65535.0, 0.5);
+             color.blue = 65535 * pow (color.blue / 65535.0, 0.5);
+#endif
+
+             /* This should be a raw XAllocColor call */
+             if (!gdk_color_alloc (cmap, &color))
+               {
+                 char tmp_str[80];
+
+                 sprintf (tmp_str, "%d %d %d colormap failed\n",
+                          nr, ng, nb);
+                 return gdk_rgb_cmap_fail (tmp_str,
+                                           cmap, pixels);
+               }
+             pixels[i] = color.pixel;
+           }
+#ifdef VERBOSE
+         g_print ("%d: %lx\n", i, pixels[i]);
+#endif
+       }
+
+  image_info->nred_shades = nr;
+  image_info->ngreen_shades = ng;
+  image_info->nblue_shades = nb;
+  gdk_rgb_make_colorcube (pixels, nr, ng, nb);
+  gdk_rgb_make_colorcube_d (pixels, nr, ng, nb);
+  return TRUE;
+}
+
+/* Return TRUE on success. */
+static gboolean
+gdk_rgb_do_colormaps (void)
+{
+  static const gint sizes[][3] = {
+    /*    { 6, 7, 6 }, */
+    { 6, 6, 6 }, 
+    { 6, 6, 5 }, 
+    { 6, 6, 4 }, 
+    { 5, 5, 5 }, 
+    { 5, 5, 4 }, 
+    { 4, 4, 4 }, 
+    { 4, 4, 3 }, 
+    { 3, 3, 3 }, 
+    { 2, 2, 2 }
+  };
+  static const gint n_sizes = sizeof(sizes) / (3 * sizeof(gint));
+  gint i;
+
+  for (i = 0; i < n_sizes; i++)
+    if (gdk_rgb_try_colormap (sizes[i][0], sizes[i][1], sizes[i][2]))
+      return TRUE;
+  return FALSE;
+}
+
+/* Make a 2 x 2 x 2 colorcube */
+static void
+gdk_rgb_colorcube_222 (void)
+{
+  int i;
+  GdkColor color;
+  GdkColormap *cmap;
+
+  if (image_info->cmap_alloced)
+    cmap = image_info->cmap;
+  else
+    cmap = gdk_colormap_get_system ();
+
+  colorcube_d = g_new (guchar, 512);
+
+  for (i = 0; i < 8; i++)
+    {
+      color.red = ((i & 4) >> 2) * 65535;
+      color.green = ((i & 2) >> 1) * 65535;
+      color.blue = (i & 1) * 65535;
+      gdk_color_alloc (cmap, &color);
+      colorcube_d[((i & 4) << 4) | ((i & 2) << 2) | (i & 1)] = color.pixel;
+    }
+}
+
+void
+gdk_rgb_set_verbose (gboolean verbose)
+{
+  gdk_rgb_verbose = verbose;
+}
+
+void
+gdk_rgb_set_install (gboolean install)
+{
+  gdk_rgb_install_cmap = install;
+}
+
+void
+gdk_rgb_set_min_colors (gint min_colors)
+{
+  gdk_rgb_min_colors = min_colors;
+}
+
+/* Return a "score" based on the following criteria (in hex):
+
+   x000 is the quality - 1 is 1bpp, 2 is 4bpp,
+                         4 is 8bpp,
+                        7 is 15bpp truecolor, 8 is 16bpp truecolor,
+                        9 is 24bpp truecolor.
+   0x00 is the speed - 1 is the normal case,
+                       2 means faster than normal
+   00x0 gets a point for being the system visual
+   000x gets a point for being pseudocolor
+
+   A caveat: in the 8bpp modes, being the system visual seems to be
+   quite important. Thus, all of the 8bpp modes should be ranked at
+   the same speed.
+*/
+static guint32
+gdk_rgb_score_visual (GdkVisual *visual)
+{
+  guint32 quality, speed, sys, pseudo;
+  static const gchar* visual_names[] =
+  {
+    "static gray",
+    "grayscale",
+    "static color",
+    "pseudo color",
+    "true color",
+    "direct color",
+  };
+
+
+  quality = 0;
+  speed = 1;
+  sys = 0;
+  if (visual->type == GDK_VISUAL_TRUE_COLOR ||
+      visual->type == GDK_VISUAL_DIRECT_COLOR)
+    {
+      if (visual->depth == 24)
+       {
+         quality = 9;
+         /* Should test for MSB visual here, and set speed if so. */
+       }
+      else if (visual->depth == 16)
+       quality = 8;
+      else if (visual->depth == 15)
+       quality = 7;
+      else if (visual->depth == 8)
+       quality = 4;
+    }
+  else if (visual->type == GDK_VISUAL_PSEUDO_COLOR ||
+          visual->type == GDK_VISUAL_STATIC_COLOR)
+    {
+      if (visual->depth == 8)
+       quality = 4;
+      else if (visual->depth == 4)
+       quality = 2;
+      else if (visual->depth == 1)
+       quality = 1;
+    }
+  else if (visual->type == GDK_VISUAL_STATIC_GRAY
+#ifdef ENABLE_GRAYSCALE
+          || visual->type == GDK_VISUAL_GRAYSCALE
+#endif
+          )
+    {
+      if (visual->depth == 8)
+       quality = 4;
+      else if (visual->depth == 4)
+       quality = 2;
+      else if (visual->depth == 1)
+       quality = 1;
+    }
+
+  if (quality == 0)
+    return 0;
+
+  sys = (visual == gdk_visual_get_system ());
+
+  pseudo = (visual->type == GDK_VISUAL_PSEUDO_COLOR || visual->type == GDK_VISUAL_TRUE_COLOR);
+
+  if (gdk_rgb_verbose)
+    g_print ("Visual 0x%x, type = %s, depth = %d, %x:%x:%x%s; score=%x\n",
+            (gint)(((GdkVisualPrivate *)visual)->xvisual->visualid),
+            visual_names[visual->type],
+            visual->depth,
+            visual->red_mask,
+            visual->green_mask,
+            visual->blue_mask,
+            sys ? " (system)" : "",
+            (quality << 12) | (speed << 8) | (sys << 4) | pseudo);
+
+  return (quality << 12) | (speed << 8) | (sys << 4) | pseudo;
+}
+
+static void
+gdk_rgb_choose_visual (void)
+{
+  GList *visuals;
+  guint32 score, best_score;
+  GdkVisual *visual, *best_visual;
+
+  visuals = gdk_list_visuals ();
+
+  best_visual = visuals->data;
+  best_score = gdk_rgb_score_visual (best_visual);
+  visuals = visuals->next;
+  while (visuals)
+    {
+      visual = visuals->data;
+      score = gdk_rgb_score_visual (visual);
+      if (score > best_score)
+       {
+         best_score = score;
+         best_visual = visual;
+       }
+      visuals = visuals->next;
+    }
+
+  image_info->visual = best_visual;
+}
+
+static void gdk_rgb_select_conv (GdkImage *image);
+
+static void
+gdk_rgb_set_gray_cmap (GdkColormap *cmap)
+{
+  gint i;
+  GdkColor color;
+  gint status;
+  gulong pixels[256];
+  gint r, g, b, gray;
+
+  for (i = 0; i < 256; i++)
+    {
+      color.pixel = i;
+      color.red = i * 257;
+      color.green = i * 257;
+      color.blue = i * 257;
+      status = gdk_color_alloc (cmap, &color);
+      pixels[i] = color.pixel;
+#ifdef VERBOSE
+      g_print ("allocating pixel %d, %x %x %x, result %d\n",
+              color.pixel, color.red, color.green, color.blue, status);
+#endif
+    }
+
+  /* Now, we make fake colorcubes - we ultimately just use the pseudocolor
+     methods. */
+
+  colorcube = g_new (guchar, 4096);
+
+  for (i = 0; i < 4096; i++)
+    {
+      r = (i >> 4) & 0xf0;
+      r = r | r >> 4;
+      g = i & 0xf0;
+      g = g | g >> 4;
+      b = (i << 4 & 0xf0);
+      b = b | b >> 4;
+      gray = (g + ((r + b) >> 1)) >> 1;
+      colorcube[i] = pixels[gray];
+    }
+}
+
+void
+gdk_rgb_init (void)
+{
+  gint i;
+  static const gint byte_order[1] = { 1 };
+
+  /* check endian sanity */
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  if (((char *)byte_order)[0] == 1)
+    g_error ("gdk_rgb_init: compiled for big endian, but this is a little endian machine.\n\n");
+#else
+  if (((char *)byte_order)[0] != 1)
+    g_error ("gdk_rgb_init: compiled for little endian, but this is a big endian machine.\n\n");
+#endif
+
+  if (image_info == NULL)
+    {
+      image_info = g_new0 (GdkRgbInfo, 1);
+
+      image_info->visual = NULL;
+      image_info->cmap = NULL;
+
+      image_info->color_pixels = NULL;
+      image_info->gray_pixels = NULL;
+      image_info->reserved_pixels = NULL;
+
+      image_info->nred_shades = 6;
+      image_info->ngreen_shades = 6;
+      image_info->nblue_shades = 4;
+      image_info->ngray_shades = 24;
+      image_info->nreserved = 0;
+
+      image_info->bpp = 0;
+      image_info->cmap_alloced = FALSE;
+      image_info->gamma = 1.0;
+
+      image_info->stage_buf = NULL;
+
+      image_info->own_gc = NULL;
+
+      gdk_rgb_choose_visual ();
+
+      if ((image_info->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
+          image_info->visual->type == GDK_VISUAL_STATIC_COLOR) &&
+         image_info->visual->depth < 8 &&
+         image_info->visual->depth >= 3)
+       {
+         image_info->cmap = gdk_colormap_get_system ();
+         gdk_rgb_colorcube_222 ();
+       }
+      else if (image_info->visual->type == GDK_VISUAL_PSEUDO_COLOR)
+       {
+         if (gdk_rgb_install_cmap ||
+             image_info->visual != gdk_visual_get_system ())
+           {
+             image_info->cmap = gdk_colormap_new (image_info->visual, FALSE);
+             image_info->cmap_alloced = TRUE;
+           }
+         if (!gdk_rgb_do_colormaps ())
+           {
+             image_info->cmap = gdk_colormap_new (image_info->visual, FALSE);
+             image_info->cmap_alloced = TRUE;
+             gdk_rgb_do_colormaps ();
+           }
+         if (gdk_rgb_verbose)
+           g_print ("color cube: %d x %d x %d\n",
+                    image_info->nred_shades,
+                    image_info->ngreen_shades,
+                    image_info->nblue_shades);
+
+         if (!image_info->cmap_alloced)
+             image_info->cmap = gdk_colormap_get_system ();
+       }
+#ifdef ENABLE_GRAYSCALE
+      else if (image_info->visual->type == GDK_VISUAL_GRAYSCALE)
+       {
+         image_info->cmap = gdk_colormap_new (image_info->visual, FALSE);
+         gdk_rgb_set_gray_cmap (image_info->cmap);
+         image_info->cmap_alloced = TRUE;
+       }
+#endif
+      else
+       {
+         /* Always install colormap in direct color. */
+         if (image_info->visual->type != GDK_VISUAL_DIRECT_COLOR &&
+             image_info->visual == gdk_visual_get_system ())
+           image_info->cmap = gdk_colormap_get_system ();
+         else
+           {
+             image_info->cmap = gdk_colormap_new (image_info->visual, FALSE);
+             image_info->cmap_alloced = TRUE;
+           }
+       }
+
+      image_info->bitmap = (image_info->visual->depth == 1);
+
+      for (i = 0; i < N_IMAGES; i++)
+       if (image_info->bitmap)
+         /* Use malloc() instead of g_malloc since X will free() this mem */
+         static_image[i] = gdk_image_new_bitmap (image_info->visual,
+                                                 (gpointer) malloc (IMAGE_WIDTH * IMAGE_HEIGHT >> 3),
+                                                 IMAGE_WIDTH, IMAGE_HEIGHT);
+       else
+         static_image[i] = gdk_image_new (GDK_IMAGE_FASTEST,
+                                          image_info->visual,
+                                          IMAGE_WIDTH, IMAGE_HEIGHT);
+
+      image_info->bpp = static_image[0]->bpp;
+
+      gdk_rgb_select_conv (static_image[0]);
+
+    }
+}
+
+/* convert an rgb value into an X pixel code */
+gulong
+gdk_rgb_xpixel_from_rgb (guint32 rgb)
+{
+  gulong pixel = 0;
+
+  if (image_info->bitmap)
+    {
+      return ((rgb & 0xff0000) >> 16) +
+       ((rgb & 0xff00) >> 7) +
+       (rgb & 0xff) > 510;
+    }
+  else if (image_info->visual->type == GDK_VISUAL_PSEUDO_COLOR)
+    pixel = colorcube[((rgb & 0xf00000) >> 12) |
+                    ((rgb & 0xf000) >> 8) |
+                    ((rgb & 0xf0) >> 4)];
+  else if (image_info->visual->depth < 8 &&
+          image_info->visual->type == GDK_VISUAL_STATIC_COLOR)
+    {
+      pixel = colorcube_d[((rgb & 0x800000) >> 17) |
+                        ((rgb & 0x8000) >> 12) |
+                        ((rgb & 0x80) >> 7)];
+    }
+  else if (image_info->visual->type == GDK_VISUAL_TRUE_COLOR ||
+          image_info->visual->type == GDK_VISUAL_DIRECT_COLOR)
+    {
+#ifdef VERBOSE
+      g_print ("shift, prec: r %d %d g %d %d b %d %d\n",
+              image_info->visual->red_shift,
+              image_info->visual->red_prec,
+              image_info->visual->green_shift,
+              image_info->visual->green_prec,
+              image_info->visual->blue_shift,
+              image_info->visual->blue_prec);
+#endif
+
+      pixel = (((((rgb & 0xff0000) >> 16) >>
+                (8 - image_info->visual->red_prec)) <<
+               image_info->visual->red_shift) +
+              ((((rgb & 0xff00) >> 8)  >>
+                (8 - image_info->visual->green_prec)) <<
+               image_info->visual->green_shift) +
+              (((rgb & 0xff) >>
+                (8 - image_info->visual->blue_prec)) <<
+               image_info->visual->blue_shift));
+    }
+  else if (image_info->visual->type == GDK_VISUAL_STATIC_GRAY ||
+          image_info->visual->type == GDK_VISUAL_GRAYSCALE)
+    {
+      int gray = ((rgb & 0xff0000) >> 16) +
+       ((rgb & 0xff00) >> 7) +
+       (rgb & 0xff);
+
+      return gray >> (10 - image_info->visual->depth);
+    }
+
+  return pixel;
+}
+
+void
+gdk_rgb_gc_set_foreground (GdkGC *gc, guint32 rgb)
+{
+  GdkColor color;
+
+  color.pixel = gdk_rgb_xpixel_from_rgb (rgb);
+  gdk_gc_set_foreground (gc, &color);
+}
+
+void
+gdk_rgb_gc_set_background (GdkGC *gc, guint32 rgb)
+{
+  GdkColor color;
+
+  color.pixel = gdk_rgb_xpixel_from_rgb (rgb);
+  gdk_gc_set_background (gc, &color);
+}
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define HAIRY_CONVERT_8
+#endif
+
+#ifdef HAIRY_CONVERT_8
+static void
+gdk_rgb_convert_8 (GdkImage *image,
+                  gint x0, gint y0, gint width, gint height,
+                  guchar *buf, int rowstride,
+                  gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  gint bpl;
+  guchar *obuf, *obptr;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+       {
+         for (x = 0; x < width; x++)
+           {
+             r = *bp2++;
+             g = *bp2++;
+             b = *bp2++;
+             obptr[0] = colorcube[((r & 0xf0) << 4) |
+                                 (g & 0xf0) |
+                                 (b >> 4)];
+             obptr++;
+           }
+       }
+      else
+       {
+         for (x = 0; x < width - 3; x += 4)
+           {
+             guint32 r1b0g0r0;
+             guint32 g2r2b1g1;
+             guint32 b3g3r3b2;
+
+             r1b0g0r0 = ((guint32 *)bp2)[0];
+             g2r2b1g1 = ((guint32 *)bp2)[1];
+             b3g3r3b2 = ((guint32 *)bp2)[2];
+             ((guint32 *)obptr)[0] =
+               colorcube[((r1b0g0r0 & 0xf0) << 4) | 
+                        ((r1b0g0r0 & 0xf000) >> 8) |
+                        ((r1b0g0r0 & 0xf00000) >> 20)] |
+               (colorcube[((r1b0g0r0 & 0xf0000000) >> 20) |
+                         (g2r2b1g1 & 0xf0) |
+                         ((g2r2b1g1 & 0xf000) >> 12)] << 8) |
+               (colorcube[((g2r2b1g1 & 0xf00000) >> 12) |
+                         ((g2r2b1g1 & 0xf0000000) >> 24) |
+                         ((b3g3r3b2 & 0xf0) >> 4)] << 16) |
+               (colorcube[((b3g3r3b2 & 0xf000) >> 4) |
+                         ((b3g3r3b2 & 0xf00000) >> 16) |
+                         (b3g3r3b2 >> 28)] << 24);
+             bp2 += 12;
+             obptr += 4;
+           }
+         for (; x < width; x++)
+           {
+             r = *bp2++;
+             g = *bp2++;
+             b = *bp2++;
+             obptr[0] = colorcube[((r & 0xf0) << 4) |
+                                 (g & 0xf0) |
+                                 (b >> 4)];
+             obptr++;
+           }
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#else
+static void
+gdk_rgb_convert_8 (GdkImage *image,
+                  gint x0, gint y0, gint width, gint height,
+                  guchar *buf, int rowstride,
+                  gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  gint bpl;
+  guchar *obuf, *obptr;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         obptr[0] = colorcube[((r & 0xf0) << 4) |
+                             (g & 0xf0) |
+                             (b >> 4)];
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#endif
+
+#if 1
+
+/* This dither table was generated by Raph Levien using patented
+   technology (US Patent 5,276,535). The dither table itself is in the
+   public domain. */
+
+#define DM_WIDTH 128
+#define DM_WIDTH_SHIFT 7
+#define DM_HEIGHT 128
+static const guchar DM[128][128] =
+{
+  { 0, 41, 23, 5, 17, 39, 7, 15, 62, 23, 40, 51, 31, 47, 9, 32, 52, 27, 57, 25, 6, 61, 27, 52, 37, 7, 40, 63, 18, 36, 10, 42, 25, 62, 45, 34, 20, 42, 37, 14, 35, 29, 50, 10, 61, 2, 40, 8, 37, 12, 58, 22, 5, 41, 10, 39, 0, 60, 11, 46, 2, 55, 38, 17, 36, 59, 13, 54, 37, 56, 8, 29, 16, 13, 63, 22, 41, 55, 7, 20, 49, 14, 23, 55, 37, 23, 19, 36, 15, 49, 23, 63, 30, 14, 38, 27, 53, 13, 22, 41, 19, 31, 7, 19, 50, 30, 49, 16, 3, 32, 56, 40, 29, 34, 8, 48, 19, 45, 4, 51, 12, 46, 35, 49, 16, 42, 12, 62 },
+  { 30, 57, 36, 54, 47, 34, 52, 27, 43, 4, 28, 7, 17, 36, 62, 13, 44, 7, 18, 48, 33, 21, 44, 14, 30, 47, 12, 33, 5, 55, 31, 58, 13, 30, 4, 17, 52, 10, 60, 26, 46, 0, 39, 27, 42, 22, 47, 25, 60, 32, 9, 38, 48, 17, 59, 30, 49, 18, 34, 25, 51, 19, 5, 48, 21, 8, 28, 46, 1, 32, 41, 19, 54, 47, 37, 18, 28, 11, 44, 30, 39, 56, 2, 33, 8, 42, 61, 28, 58, 8, 46, 9, 41, 4, 58, 7, 21, 48, 59, 10, 52, 14, 42, 57, 12, 25, 7, 53, 42, 24, 11, 50, 17, 59, 42, 2, 36, 60, 32, 17, 63, 29, 21, 7, 59, 32, 24, 39 },
+  { 22, 8, 16, 32, 3, 25, 13, 57, 18, 45, 58, 39, 55, 20, 5, 42, 23, 34, 63, 1, 51, 10, 58, 4, 60, 23, 53, 27, 44, 21, 3, 48, 8, 50, 43, 54, 27, 32, 5, 55, 21, 58, 12, 53, 6, 36, 14, 50, 17, 29, 53, 15, 24, 52, 7, 36, 13, 42, 4, 53, 9, 35, 61, 26, 56, 32, 49, 15, 62, 23, 6, 60, 2, 31, 4, 48, 58, 38, 15, 61, 5, 25, 47, 28, 50, 15, 7, 40, 3, 32, 33, 52, 25, 50, 35, 42, 61, 3, 28, 36, 23, 63, 4, 33, 46, 62, 36, 23, 60, 6, 54, 28, 4, 37, 23, 55, 25, 8, 42, 54, 14, 6, 56, 38, 19, 52, 4, 46 },
+  { 48, 53, 43, 12, 45, 63, 30, 37, 9, 34, 21, 1, 25, 47, 29, 58, 3, 54, 15, 39, 29, 17, 38, 35, 20, 43, 1, 49, 15, 59, 29, 39, 22, 35, 16, 23, 1, 47, 39, 18, 8, 44, 25, 31, 57, 19, 63, 4, 45, 3, 42, 61, 1, 31, 45, 20, 57, 29, 62, 21, 32, 41, 14, 44, 3, 39, 5, 34, 10, 43, 51, 35, 23, 52, 40, 10, 21, 1, 53, 18, 51, 43, 12, 62, 18, 54, 26, 51, 20, 57, 14, 1, 62, 16, 11, 18, 32, 39, 17, 44, 1, 48, 26, 37, 18, 2, 51, 14, 28, 45, 35, 18, 57, 13, 47, 11, 51, 20, 2, 39, 31, 47, 25, 1, 50, 11, 60, 7 },
+  { 18, 28, 1, 56, 21, 10, 51, 2, 46, 54, 14, 61, 11, 50, 13, 38, 19, 31, 45, 9, 55, 24, 47, 5, 54, 9, 62, 11, 35, 8, 51, 14, 57, 6, 63, 40, 58, 14, 51, 28, 62, 34, 15, 48, 1, 41, 30, 35, 55, 21, 34, 11, 49, 37, 8, 52, 4, 23, 15, 43, 1, 58, 11, 23, 53, 16, 55, 26, 58, 18, 27, 12, 45, 14, 25, 63, 42, 33, 27, 35, 9, 31, 21, 38, 1, 44, 34, 12, 48, 38, 21, 44, 29, 47, 26, 53, 1, 46, 54, 8, 59, 29, 11, 55, 22, 41, 33, 20, 39, 1, 48, 9, 44, 32, 5, 62, 29, 44, 57, 23, 10, 58, 34, 43, 15, 37, 26, 33 },
+  { 51, 38, 59, 24, 35, 42, 19, 60, 5, 32, 41, 26, 43, 33, 7, 53, 48, 11, 59, 23, 42, 2, 61, 30, 16, 40, 32, 24, 56, 41, 19, 33, 37, 26, 47, 9, 31, 22, 2, 45, 9, 54, 4, 37, 21, 52, 11, 23, 7, 57, 16, 25, 55, 18, 63, 27, 46, 39, 56, 10, 50, 37, 29, 47, 19, 63, 24, 9, 46, 2, 39, 60, 9, 57, 30, 7, 49, 11, 59, 3, 45, 57, 5, 60, 29, 22, 5, 60, 30, 9, 59, 18, 40, 6, 57, 36, 30, 12, 24, 34, 15, 40, 52, 6, 49, 9, 58, 4, 63, 12, 26, 61, 22, 53, 38, 16, 35, 14, 28, 50, 42, 17, 5, 28, 62, 20, 54, 12 },
+  { 26, 6, 31, 15, 49, 6, 38, 27, 22, 49, 16, 56, 2, 62, 30, 21, 0, 36, 28, 6, 49, 32, 13, 52, 26, 50, 19, 46, 3, 26, 62, 0, 53, 12, 29, 3, 53, 41, 60, 24, 38, 13, 58, 16, 43, 9, 59, 39, 46, 28, 44, 40, 2, 33, 13, 41, 16, 6, 47, 31, 26, 17, 57, 6, 38, 0, 42, 36, 29, 52, 20, 31, 48, 0, 34, 56, 20, 36, 23, 54, 14, 41, 24, 37, 10, 55, 46, 25, 16, 45, 36, 4, 55, 23, 15, 8, 50, 62, 5, 56, 44, 20, 13, 28, 59, 31, 24, 47, 31, 52, 37, 17, 40, 0, 26, 49, 3, 60, 7, 33, 0, 61, 53, 40, 8, 45, 2, 41 },
+  { 16, 63, 43, 4, 61, 24, 56, 13, 53, 8, 36, 12, 24, 41, 16, 46, 60, 26, 52, 39, 14, 57, 21, 37, 0, 45, 7, 59, 38, 17, 43, 10, 45, 20, 61, 43, 19, 11, 33, 17, 50, 32, 23, 61, 28, 49, 26, 0, 18, 51, 5, 60, 22, 58, 29, 0, 59, 34, 19, 62, 3, 52, 7, 44, 30, 59, 13, 50, 15, 62, 7, 17, 38, 22, 44, 15, 40, 4, 47, 28, 33, 17, 49, 16, 51, 40, 10, 56, 0, 53, 13, 49, 28, 38, 60, 21, 43, 19, 37, 27, 3, 51, 34, 39, 0, 45, 15, 43, 10, 21, 3, 55, 8, 33, 59, 10, 41, 18, 52, 24, 46, 20, 30, 13, 58, 22, 36, 57 },
+  { 50, 34, 11, 47, 29, 17, 44, 0, 33, 63, 28, 46, 52, 5, 57, 10, 42, 18, 4, 63, 20, 8, 44, 10, 56, 34, 14, 29, 5, 54, 23, 59, 32, 49, 7, 34, 49, 27, 56, 0, 42, 7, 46, 3, 40, 6, 54, 32, 62, 13, 36, 10, 47, 8, 35, 49, 24, 51, 12, 40, 22, 35, 60, 12, 22, 51, 33, 4, 40, 25, 43, 55, 5, 54, 12, 61, 26, 51, 8, 62, 0, 53, 7, 63, 2, 32, 19, 34, 42, 24, 31, 63, 2, 10, 45, 33, 0, 48, 9, 61, 22, 47, 8, 62, 18, 56, 7, 54, 27, 57, 46, 30, 50, 19, 45, 30, 56, 36, 22, 47, 11, 38, 3, 51, 32, 48, 18, 9 },
+  { 0, 21, 40, 19, 52, 9, 37, 48, 20, 40, 3, 18, 27, 38, 35, 22, 31, 56, 13, 35, 46, 28, 60, 40, 27, 18, 61, 50, 41, 30, 7, 36, 2, 25, 16, 57, 5, 15, 47, 29, 55, 19, 30, 52, 15, 34, 20, 12, 43, 30, 20, 54, 25, 44, 53, 12, 38, 5, 55, 27, 48, 15, 33, 27, 45, 8, 19, 28, 56, 11, 33, 49, 18, 36, 29, 2, 45, 16, 39, 19, 31, 43, 27, 35, 20, 52, 26, 6, 61, 11, 41, 17, 29, 51, 20, 56, 25, 32, 41, 17, 53, 31, 25, 14, 42, 23, 35, 16, 38, 6, 34, 12, 15, 62, 6, 21, 13, 1, 63, 9, 55, 27, 43, 25, 14, 4, 31, 55 },
+  { 44, 29, 61, 2, 35, 58, 26, 15, 60, 10, 51, 59, 14, 55, 8, 50, 2, 44, 25, 51, 1, 33, 16, 4, 48, 36, 2, 21, 12, 57, 48, 13, 51, 55, 40, 28, 37, 62, 8, 39, 12, 63, 36, 10, 59, 24, 56, 47, 9, 50, 41, 1, 32, 17, 6, 21, 61, 30, 9, 43, 1, 54, 41, 2, 54, 37, 48, 61, 1, 46, 21, 3, 58, 24, 50, 32, 60, 10, 57, 25, 46, 12, 59, 4, 45, 13, 57, 47, 27, 39, 5, 58, 47, 14, 35, 4, 52, 13, 60, 6, 36, 10, 45, 55, 4, 50, 29, 2, 61, 50, 25, 58, 44, 24, 36, 42, 54, 28, 40, 32, 16, 56, 6, 62, 46, 39, 60, 23 },
+  { 7, 48, 14, 54, 23, 40, 4, 45, 30, 22, 42, 32, 1, 44, 20, 29, 58, 8, 37, 19, 41, 54, 24, 58, 9, 53, 25, 46, 34, 16, 23, 38, 27, 11, 18, 1, 52, 21, 35, 22, 48, 5, 25, 45, 18, 38, 2, 27, 35, 4, 57, 15, 62, 39, 57, 28, 42, 16, 36, 60, 24, 18, 10, 63, 20, 5, 16, 23, 37, 14, 59, 27, 41, 8, 13, 42, 21, 35, 6, 50, 3, 38, 15, 48, 30, 39, 17, 3, 49, 14, 53, 33, 24, 7, 61, 44, 11, 39, 23, 49, 19, 58, 1, 32, 36, 12, 60, 41, 20, 13, 41, 4, 39, 1, 48, 8, 18, 51, 14, 44, 5, 37, 21, 34, 1, 26, 10, 37 },
+  { 53, 36, 27, 9, 50, 12, 32, 55, 2, 57, 7, 17, 48, 34, 63, 15, 40, 26, 62, 11, 49, 6, 31, 39, 22, 42, 6, 63, 1, 39, 60, 4, 42, 61, 32, 45, 24, 44, 2, 60, 16, 41, 53, 1, 33, 61, 49, 17, 63, 23, 45, 26, 33, 3, 23, 46, 2, 50, 20, 4, 45, 34, 49, 30, 39, 58, 44, 31, 53, 34, 6, 52, 30, 47, 63, 1, 53, 22, 42, 31, 58, 23, 54, 22, 61, 8, 36, 59, 22, 35, 21, 1, 55, 40, 27, 16, 30, 54, 2, 29, 43, 16, 39, 63, 21, 46, 26, 10, 48, 32, 19, 53, 30, 56, 26, 60, 33, 4, 61, 23, 49, 59, 15, 53, 19, 58, 42, 16 },
+  { 20, 5, 59, 46, 25, 62, 7, 19, 43, 25, 37, 61, 11, 24, 4, 54, 12, 52, 3, 32, 17, 61, 12, 47, 15, 55, 18, 31, 53, 28, 9, 50, 21, 6, 55, 9, 58, 14, 54, 26, 33, 7, 31, 58, 13, 21, 8, 42, 29, 6, 37, 11, 48, 52, 14, 60, 11, 39, 56, 32, 14, 58, 7, 26, 17, 4, 42, 8, 11, 47, 19, 38, 10, 17, 26, 37, 9, 55, 28, 13, 18, 40, 6, 33, 1, 43, 25, 11, 51, 7, 62, 43, 18, 37, 3, 57, 45, 9, 38, 58, 5, 52, 27, 7, 17, 53, 5, 57, 37, 2, 63, 9, 22, 15, 11, 38, 25, 45, 35, 0, 28, 10, 41, 30, 50, 8, 31, 57 },
+  { 49, 33, 16, 38, 1, 42, 51, 34, 53, 14, 28, 49, 30, 56, 36, 23, 43, 20, 38, 56, 22, 45, 28, 0, 62, 35, 26, 44, 11, 19, 52, 35, 44, 15, 30, 38, 10, 31, 40, 4, 46, 50, 20, 40, 27, 44, 51, 14, 56, 53, 19, 59, 7, 29, 41, 19, 35, 25, 8, 52, 22, 44, 13, 53, 50, 32, 61, 24, 56, 25, 63, 0, 45, 57, 33, 59, 16, 46, 4, 62, 50, 11, 60, 37, 52, 19, 55, 29, 37, 46, 13, 26, 48, 10, 50, 34, 21, 63, 26, 13, 42, 33, 22, 55, 35, 28, 43, 15, 24, 51, 27, 34, 46, 49, 58, 3, 52, 9, 57, 19, 48, 55, 3, 35, 12, 45, 24, 3 },
+  { 41, 11, 56, 28, 18, 31, 22, 10, 37, 6, 47, 13, 3, 41, 9, 46, 0, 48, 29, 6, 34, 10, 55, 37, 20, 8, 49, 3, 41, 59, 14, 25, 0, 63, 19, 47, 27, 51, 17, 57, 23, 10, 61, 6, 54, 3, 38, 31, 0, 22, 34, 43, 20, 55, 31, 0, 49, 63, 29, 38, 3, 62, 28, 40, 0, 22, 14, 35, 2, 48, 15, 43, 23, 14, 3, 29, 49, 20, 39, 34, 0, 44, 29, 9, 15, 47, 5, 42, 0, 31, 58, 5, 31, 61, 23, 15, 0, 47, 19, 50, 24, 3, 59, 11, 44, 0, 31, 59, 6, 42, 17, 60, 0, 39, 20, 31, 43, 17, 29, 40, 12, 25, 60, 22, 52, 15, 63, 29 },
+  { 20, 52, 8, 44, 62, 4, 59, 49, 17, 63, 21, 39, 60, 18, 52, 27, 33, 59, 14, 51, 59, 43, 24, 5, 51, 30, 57, 17, 32, 5, 37, 56, 48, 34, 42, 3, 60, 5, 36, 13, 43, 37, 18, 34, 25, 12, 59, 24, 47, 36, 11, 50, 3, 38, 9, 58, 16, 5, 43, 18, 47, 10, 37, 18, 59, 46, 29, 52, 40, 12, 34, 28, 56, 36, 53, 7, 43, 8, 24, 52, 26, 17, 56, 43, 24, 32, 63, 20, 57, 16, 22, 52, 36, 8, 41, 56, 29, 32, 54, 7, 35, 57, 14, 48, 20, 62, 13, 39, 53, 29, 8, 45, 13, 29, 7, 61, 14, 54, 6, 63, 38, 32, 18, 43, 2, 39, 6, 47 },
+  { 0, 58, 23, 35, 13, 46, 12, 39, 0, 31, 55, 24, 5, 35, 15, 61, 17, 5, 39, 25, 18, 2, 50, 33, 41, 13, 39, 23, 62, 46, 29, 12, 22, 8, 56, 25, 20, 49, 32, 62, 0, 56, 11, 46, 63, 42, 9, 16, 55, 5, 60, 15, 62, 26, 45, 21, 36, 51, 13, 57, 31, 24, 55, 6, 35, 9, 57, 5, 20, 60, 7, 51, 5, 19, 40, 25, 61, 32, 56, 12, 36, 48, 21, 2, 58, 12, 39, 28, 9, 50, 40, 12, 44, 18, 25, 49, 6, 38, 11, 62, 18, 46, 30, 9, 40, 25, 49, 19, 10, 36, 55, 22, 33, 52, 41, 18, 37, 27, 49, 21, 2, 46, 7, 53, 33, 61, 27, 35 },
+  { 41, 31, 5, 39, 51, 26, 33, 57, 27, 41, 9, 44, 54, 29, 48, 7, 44, 36, 57, 10, 31, 63, 16, 45, 11, 60, 1, 47, 7, 20, 43, 3, 58, 36, 13, 52, 39, 7, 15, 28, 22, 48, 30, 21, 1, 29, 49, 44, 27, 17, 40, 30, 24, 42, 12, 53, 33, 7, 47, 20, 1, 42, 11, 49, 25, 43, 17, 32, 45, 27, 41, 21, 31, 62, 11, 49, 2, 15, 42, 5, 63, 7, 41, 27, 49, 6, 54, 23, 46, 34, 2, 28, 54, 3, 59, 12, 46, 17, 42, 28, 40, 1, 37, 51, 5, 55, 2, 34, 47, 16, 3, 62, 47, 5, 23, 56, 1, 44, 12, 34, 51, 16, 57, 11, 25, 17, 54, 13 },
+  { 60, 26, 55, 18, 3, 60, 20, 6, 52, 15, 50, 19, 32, 11, 23, 53, 26, 21, 1, 47, 42, 27, 8, 58, 21, 27, 53, 36, 26, 54, 31, 50, 17, 30, 45, 1, 29, 59, 44, 53, 41, 4, 35, 58, 51, 19, 32, 4, 52, 34, 48, 8, 51, 5, 56, 2, 25, 61, 27, 38, 54, 27, 62, 21, 51, 1, 39, 62, 10, 50, 1, 58, 13, 47, 38, 18, 35, 54, 22, 51, 30, 19, 59, 34, 14, 32, 44, 4, 60, 15, 52, 62, 20, 43, 30, 35, 21, 60, 4, 52, 12, 24, 61, 18, 30, 42, 23, 61, 25, 50, 27, 38, 11, 59, 12, 35, 50, 30, 59, 24, 8, 42, 28, 37, 48, 9, 44, 21 },
+  { 10, 47, 15, 50, 30, 43, 8, 45, 29, 2, 36, 59, 1, 58, 41, 3, 63, 31, 54, 20, 13, 55, 35, 38, 4, 44, 15, 9, 61, 2, 14, 38, 61, 10, 23, 54, 18, 12, 24, 2, 14, 55, 16, 8, 38, 14, 41, 60, 10, 23, 1, 58, 32, 17, 28, 37, 41, 15, 3, 60, 15, 33, 4, 36, 16, 59, 28, 14, 23, 55, 37, 18, 44, 28, 2, 57, 30, 10, 27, 46, 14, 38, 3, 53, 21, 61, 17, 35, 10, 41, 26, 7, 33, 9, 57, 1, 53, 37, 26, 20, 56, 48, 9, 33, 58, 16, 37, 7, 45, 1, 57, 15, 32, 26, 42, 23, 7, 20, 4, 54, 31, 62, 22, 1, 59, 30, 4, 51 },
+  { 36, 2, 38, 11, 24, 36, 54, 22, 62, 47, 25, 8, 28, 45, 16, 38, 12, 43, 9, 37, 49, 3, 23, 52, 18, 30, 50, 33, 19, 42, 49, 26, 6, 40, 47, 35, 63, 38, 50, 33, 60, 26, 36, 47, 24, 57, 6, 26, 39, 63, 19, 44, 14, 46, 61, 9, 50, 30, 45, 23, 10, 50, 44, 8, 31, 54, 6, 46, 36, 4, 30, 54, 8, 52, 22, 41, 4, 60, 40, 0, 58, 24, 45, 10, 37, 1, 48, 30, 56, 17, 38, 48, 24, 47, 19, 39, 14, 8, 45, 32, 2, 34, 27, 44, 4, 52, 11, 56, 31, 21, 40, 19, 44, 51, 2, 63, 46, 58, 36, 43, 14, 5, 50, 38, 14, 56, 40, 23 },
+  { 61, 46, 32, 63, 54, 1, 14, 34, 12, 40, 18, 49, 37, 10, 61, 30, 51, 24, 60, 7, 29, 40, 62, 11, 46, 58, 6, 56, 24, 10, 34, 52, 21, 59, 16, 3, 27, 5, 20, 46, 9, 40, 7, 62, 2, 30, 53, 15, 48, 10, 28, 35, 54, 6, 21, 34, 18, 55, 7, 40, 57, 19, 26, 60, 41, 13, 24, 51, 19, 61, 9, 25, 34, 15, 63, 11, 45, 17, 20, 47, 33, 8, 31, 62, 43, 26, 53, 7, 24, 59, 0, 13, 55, 4, 62, 27, 51, 31, 63, 15, 58, 7, 54, 14, 46, 22, 28, 43, 12, 63, 8, 54, 5, 17, 39, 33, 15, 10, 27, 17, 47, 34, 19, 45, 27, 12, 33, 17 },
+  { 5, 28, 21, 7, 17, 48, 42, 58, 23, 4, 63, 14, 55, 21, 34, 5, 19, 0, 45, 17, 52, 15, 25, 32, 0, 22, 40, 13, 45, 62, 18, 0, 43, 11, 33, 55, 30, 42, 57, 19, 51, 31, 22, 43, 18, 45, 34, 0, 43, 31, 56, 3, 23, 40, 59, 0, 44, 13, 48, 35, 2, 32, 46, 0, 21, 48, 35, 3, 40, 32, 43, 59, 0, 48, 33, 26, 53, 36, 55, 12, 51, 16, 55, 5, 18, 29, 11, 39, 51, 19, 45, 31, 42, 21, 35, 6, 22, 47, 10, 38, 23, 50, 20, 36, 0, 60, 38, 4, 50, 35, 48, 34, 24, 57, 9, 53, 28, 48, 61, 0, 56, 24, 53, 3, 63, 6, 42, 57 },
+  { 13, 53, 45, 40, 58, 27, 6, 16, 38, 51, 33, 30, 43, 2, 47, 56, 40, 50, 33, 57, 27, 5, 47, 42, 60, 36, 16, 54, 28, 4, 37, 57, 28, 51, 22, 8, 45, 14, 6, 39, 0, 54, 11, 59, 28, 12, 50, 21, 61, 13, 19, 38, 49, 11, 25, 37, 58, 29, 22, 63, 14, 56, 12, 53, 30, 63, 9, 57, 26, 12, 47, 16, 23, 39, 50, 6, 31, 2, 25, 6, 28, 41, 36, 22, 50, 57, 42, 3, 34, 8, 28, 61, 11, 50, 16, 54, 41, 0, 55, 43, 5, 29, 41, 63, 25, 16, 53, 18, 26, 10, 21, 0, 61, 30, 41, 22, 3, 38, 20, 39, 29, 8, 41, 16, 36, 52, 22, 19 },
+  { 55, 34, 0, 25, 10, 32, 56, 44, 28, 0, 57, 7, 26, 53, 23, 8, 13, 35, 22, 12, 36, 60, 20, 8, 14, 29, 48, 2, 41, 49, 23, 13, 39, 7, 48, 58, 25, 53, 34, 62, 28, 16, 48, 4, 37, 56, 27, 5, 36, 52, 46, 7, 62, 33, 52, 11, 17, 53, 5, 28, 41, 24, 38, 17, 5, 39, 20, 45, 15, 56, 5, 38, 60, 8, 14, 57, 21, 48, 62, 39, 59, 13, 1, 60, 9, 32, 16, 63, 44, 25, 52, 15, 36, 2, 60, 29, 12, 33, 25, 17, 59, 45, 13, 8, 49, 32, 6, 40, 59, 29, 45, 37, 13, 47, 6, 55, 30, 45, 9, 52, 13, 59, 25, 47, 32, 1, 49, 30 },
+  { 9, 39, 14, 61, 49, 37, 3, 20, 50, 13, 41, 19, 46, 17, 38, 59, 28, 62, 4, 44, 54, 1, 34, 51, 55, 7, 63, 32, 21, 8, 56, 31, 62, 19, 36, 1, 41, 17, 24, 12, 42, 35, 25, 52, 20, 8, 44, 59, 25, 2, 22, 42, 16, 29, 4, 46, 20, 36, 43, 9, 51, 8, 49, 26, 58, 33, 54, 1, 37, 29, 52, 20, 27, 45, 19, 35, 42, 16, 10, 32, 20, 49, 46, 27, 40, 4, 47, 22, 13, 55, 4, 47, 26, 44, 23, 40, 58, 19, 48, 13, 31, 2, 57, 34, 42, 19, 61, 32, 14, 55, 5, 51, 26, 19, 58, 16, 49, 14, 62, 5, 33, 44, 21, 7, 60, 26, 11, 41 },
+  { 62, 24, 47, 29, 8, 19, 53, 11, 60, 24, 32, 61, 4, 55, 31, 2, 49, 16, 39, 9, 31, 24, 43, 17, 26, 38, 11, 25, 58, 43, 12, 35, 3, 46, 15, 32, 63, 4, 49, 56, 2, 60, 10, 32, 63, 17, 39, 12, 55, 30, 57, 9, 48, 55, 39, 24, 60, 2, 58, 31, 19, 61, 34, 3, 42, 11, 22, 46, 7, 61, 10, 42, 3, 55, 32, 1, 58, 28, 44, 54, 4, 34, 23, 15, 56, 20, 37, 58, 6, 30, 38, 18, 63, 9, 32, 5, 51, 3, 62, 37, 52, 18, 39, 23, 3, 51, 9, 47, 1, 23, 43, 15, 60, 35, 11, 40, 1, 36, 31, 26, 57, 2, 37, 54, 18, 44, 58, 16 },
+  { 5, 51, 3, 33, 43, 62, 21, 42, 35, 9, 48, 15, 36, 10, 22, 42, 20, 46, 26, 56, 50, 12, 59, 3, 48, 19, 45, 53, 1, 27, 47, 17, 52, 24, 56, 11, 51, 21, 37, 30, 20, 46, 14, 41, 1, 47, 33, 7, 41, 17, 35, 27, 20, 1, 14, 54, 26, 33, 18, 47, 1, 44, 14, 59, 16, 52, 28, 18, 49, 31, 25, 34, 63, 13, 51, 24, 9, 50, 3, 23, 38, 63, 7, 52, 29, 46, 11, 33, 50, 22, 57, 36, 1, 57, 49, 17, 39, 28, 9, 35, 6, 27, 53, 15, 55, 30, 24, 58, 36, 41, 11, 52, 32, 3, 44, 25, 62, 23, 51, 15, 42, 22, 50, 10, 39, 4, 31, 35 },
+  { 46, 22, 57, 17, 12, 39, 26, 5, 31, 59, 1, 45, 27, 62, 52, 7, 58, 33, 6, 18, 39, 22, 33, 41, 57, 5, 35, 18, 40, 16, 60, 5, 29, 42, 7, 39, 27, 44, 9, 47, 8, 26, 54, 22, 51, 29, 24, 49, 15, 61, 4, 51, 31, 63, 43, 6, 50, 8, 39, 12, 53, 37, 23, 30, 40, 6, 62, 43, 14, 53, 2, 49, 7, 36, 17, 41, 61, 37, 18, 56, 11, 18, 44, 35, 2, 19, 61, 0, 41, 14, 8, 30, 43, 12, 24, 46, 14, 54, 42, 21, 44, 61, 10, 46, 37, 11, 44, 7, 18, 63, 20, 29, 7, 49, 28, 54, 8, 43, 4, 48, 18, 63, 12, 29, 48, 24, 59, 20 },
+  { 13, 36, 28, 54, 35, 2, 56, 46, 16, 49, 22, 40, 11, 34, 14, 43, 29, 12, 63, 48, 2, 61, 7, 15, 28, 30, 50, 9, 61, 33, 38, 23, 54, 13, 61, 33, 3, 59, 16, 35, 58, 40, 5, 38, 13, 57, 3, 58, 37, 21, 45, 12, 39, 7, 35, 30, 13, 56, 22, 62, 27, 6, 55, 10, 48, 21, 33, 2, 38, 23, 40, 20, 44, 29, 59, 4, 26, 12, 33, 47, 28, 53, 31, 13, 59, 41, 27, 49, 26, 54, 45, 16, 53, 21, 35, 7, 59, 26, 11, 56, 1, 24, 33, 4, 28, 62, 21, 49, 31, 2, 56, 39, 24, 58, 13, 17, 37, 21, 56, 10, 38, 0, 34, 55, 15, 43, 1, 52 },
+  { 42, 9, 50, 6, 25, 60, 14, 38, 10, 29, 53, 18, 57, 3, 25, 51, 0, 53, 25, 17, 29, 37, 52, 46, 0, 62, 14, 37, 4, 50, 10, 44, 0, 46, 20, 25, 50, 19, 55, 0, 23, 31, 62, 34, 11, 45, 19, 32, 0, 53, 10, 59, 23, 47, 18, 60, 42, 28, 37, 3, 50, 15, 35, 44, 0, 51, 27, 60, 9, 57, 16, 58, 11, 22, 46, 15, 53, 48, 7, 42, 0, 60, 5, 49, 24, 54, 9, 17, 39, 5, 34, 62, 3, 40, 60, 31, 0, 47, 29, 16, 49, 39, 59, 17, 50, 0, 40, 13, 53, 38, 16, 46, 0, 42, 34, 60, 2, 53, 29, 31, 58, 46, 27, 6, 61, 8, 37, 28 },
+  { 0, 63, 21, 40, 45, 18, 51, 23, 63, 34, 6, 43, 28, 38, 55, 19, 40, 35, 8, 41, 54, 10, 21, 32, 39, 23, 53, 26, 55, 28, 22, 63, 30, 34, 9, 48, 6, 38, 29, 43, 49, 6, 18, 52, 27, 61, 9, 43, 28, 42, 33, 26, 56, 3, 51, 23, 0, 48, 16, 45, 32, 25, 63, 20, 57, 17, 42, 12, 35, 47, 5, 31, 39, 56, 6, 30, 34, 21, 61, 25, 14, 40, 22, 38, 15, 6, 36, 56, 20, 60, 25, 12, 51, 27, 10, 56, 42, 20, 36, 63, 32, 6, 21, 41, 12, 34, 60, 26, 5, 48, 27, 10, 62, 19, 6, 47, 39, 14, 45, 7, 24, 17, 41, 32, 23, 51, 19, 56 },
+  { 45, 31, 15, 59, 4, 33, 7, 47, 0, 41, 13, 61, 4, 47, 9, 23, 60, 14, 57, 31, 4, 45, 59, 6, 58, 10, 44, 20, 8, 42, 15, 6, 55, 17, 58, 31, 53, 12, 61, 10, 15, 57, 43, 2, 23, 35, 48, 14, 54, 6, 18, 49, 15, 38, 11, 34, 62, 9, 21, 58, 11, 41, 4, 31, 38, 8, 29, 55, 19, 36, 27, 52, 0, 25, 50, 43, 1, 39, 8, 55, 35, 51, 10, 30, 45, 62, 29, 2, 46, 10, 32, 48, 18, 38, 5, 22, 33, 8, 51, 3, 14, 44, 54, 25, 57, 30, 18, 52, 33, 22, 59, 28, 36, 52, 32, 21, 26, 50, 5, 55, 35, 60, 14, 54, 4, 40, 16, 33 },
+  { 27, 3, 49, 10, 30, 40, 55, 27, 57, 24, 52, 21, 32, 17, 60, 30, 5, 44, 27, 49, 19, 34, 13, 24, 43, 36, 3, 49, 31, 59, 37, 48, 26, 41, 2, 41, 14, 36, 21, 32, 40, 26, 13, 49, 55, 5, 16, 40, 25, 60, 36, 1, 63, 29, 17, 44, 25, 40, 52, 5, 29, 47, 54, 13, 46, 24, 60, 4, 51, 22, 63, 14, 45, 18, 12, 62, 17, 57, 19, 42, 3, 26, 58, 48, 1, 21, 40, 52, 23, 37, 44, 1, 29, 58, 43, 50, 15, 61, 19, 45, 58, 28, 7, 48, 2, 46, 8, 42, 3, 55, 8, 50, 12, 4, 55, 10, 63, 33, 20, 40, 11, 3, 46, 20, 48, 26, 61, 11 },
+  { 44, 56, 24, 36, 53, 19, 12, 37, 16, 44, 7, 36, 49, 54, 11, 37, 48, 21, 15, 1, 62, 25, 47, 56, 16, 18, 51, 12, 40, 1, 24, 11, 52, 16, 23, 59, 28, 1, 45, 53, 4, 60, 37, 21, 39, 30, 63, 20, 52, 10, 30, 45, 8, 41, 54, 4, 57, 7, 34, 55, 36, 18, 23, 59, 2, 48, 11, 32, 44, 1, 41, 8, 33, 54, 38, 23, 30, 46, 6, 29, 62, 18, 32, 16, 55, 34, 14, 11, 61, 7, 55, 16, 53, 13, 23, 2, 55, 37, 26, 10, 33, 23, 36, 16, 38, 22, 56, 15, 24, 43, 35, 17, 44, 40, 25, 46, 16, 1, 57, 25, 49, 36, 28, 62, 9, 35, 7, 53 },
+  { 17, 38, 8, 61, 1, 50, 26, 62, 3, 31, 56, 15, 1, 26, 40, 2, 34, 51, 56, 36, 42, 9, 38, 2, 29, 60, 32, 57, 19, 62, 34, 47, 4, 57, 39, 7, 44, 63, 24, 18, 46, 28, 8, 54, 1, 34, 7, 46, 3, 37, 50, 23, 57, 21, 13, 46, 31, 20, 43, 15, 1, 61, 8, 33, 37, 17, 56, 26, 15, 49, 24, 59, 28, 3, 56, 9, 52, 32, 13, 49, 10, 43, 5, 45, 8, 25, 59, 42, 28, 33, 19, 40, 8, 63, 35, 47, 25, 4, 40, 52, 1, 60, 12, 53, 63, 9, 29, 60, 37, 19, 1, 62, 31, 20, 58, 12, 41, 30, 43, 9, 18, 52, 22, 1, 39, 30, 58, 21 },
+  { 13, 47, 29, 18, 43, 34, 5, 48, 20, 42, 10, 45, 30, 58, 20, 63, 24, 11, 6, 28, 54, 14, 22, 52, 41, 7, 26, 5, 45, 15, 53, 13, 35, 27, 18, 50, 12, 33, 5, 56, 10, 17, 45, 24, 59, 15, 50, 26, 56, 13, 19, 5, 32, 52, 27, 36, 2, 61, 12, 26, 49, 40, 27, 52, 13, 50, 6, 39, 61, 34, 10, 37, 48, 20, 41, 27, 2, 36, 59, 24, 54, 33, 63, 20, 38, 50, 3, 17, 52, 4, 58, 27, 45, 21, 32, 11, 48, 17, 57, 20, 46, 38, 25, 43, 4, 34, 51, 6, 13, 45, 57, 26, 6, 48, 2, 35, 53, 23, 61, 34, 59, 6, 42, 56, 13, 51, 2, 41 },
+  { 32, 5, 55, 23, 58, 14, 22, 52, 29, 15, 61, 25, 51, 8, 43, 13, 53, 41, 46, 20, 3, 33, 63, 11, 48, 21, 54, 38, 28, 3, 30, 43, 21, 62, 9, 31, 55, 22, 51, 29, 37, 62, 32, 12, 42, 29, 41, 9, 33, 44, 62, 28, 43, 1, 59, 19, 48, 30, 51, 39, 24, 4, 58, 19, 42, 29, 22, 43, 3, 18, 53, 5, 13, 50, 16, 60, 45, 21, 7, 40, 15, 0, 26, 53, 13, 31, 43, 24, 47, 31, 15, 49, 2, 41, 6, 59, 29, 42, 9, 30, 14, 7, 49, 18, 31, 47, 20, 39, 49, 32, 11, 41, 54, 15, 61, 18, 7, 38, 4, 13, 44, 28, 15, 32, 45, 19, 27, 49 },
+  { 63, 34, 11, 39, 2, 45, 37, 8, 59, 39, 33, 4, 36, 17, 48, 5, 29, 18, 32, 61, 39, 50, 5, 27, 35, 0, 46, 12, 22, 49, 60, 6, 54, 0, 38, 49, 2, 42, 15, 40, 0, 47, 20, 51, 3, 57, 18, 61, 22, 0, 39, 16, 55, 12, 35, 8, 41, 22, 6, 59, 16, 45, 10, 36, 0, 62, 9, 54, 30, 58, 21, 43, 63, 31, 7, 35, 12, 48, 58, 28, 47, 37, 41, 9, 57, 20, 61, 0, 36, 11, 57, 35, 23, 52, 37, 18, 0, 62, 22, 55, 35, 62, 27, 54, 0, 15, 61, 28, 2, 59, 22, 9, 37, 27, 33, 51, 29, 48, 19, 50, 25, 37, 10, 57, 5, 37, 60, 8 },
+  { 20, 25, 46, 52, 31, 60, 12, 55, 0, 19, 11, 46, 62, 35, 23, 38, 57, 0, 55, 10, 16, 30, 58, 44, 17, 59, 29, 63, 42, 8, 36, 20, 33, 46, 16, 61, 25, 35, 8, 54, 26, 7, 58, 22, 34, 6, 47, 14, 53, 31, 48, 9, 37, 25, 49, 63, 16, 55, 45, 14, 34, 63, 21, 53, 25, 33, 46, 16, 35, 7, 46, 29, 0, 39, 25, 55, 22, 34, 18, 4, 56, 11, 23, 51, 28, 6, 39, 14, 62, 44, 19, 8, 60, 12, 56, 28, 50, 34, 39, 5, 51, 3, 41, 12, 57, 35, 10, 53, 25, 17, 52, 30, 47, 0, 43, 14, 5, 57, 31, 55, 0, 63, 47, 23, 54, 24, 14, 43 },
+  { 0, 57, 16, 6, 26, 19, 35, 28, 49, 42, 54, 26, 21, 1, 59, 27, 9, 47, 26, 44, 50, 22, 13, 40, 8, 37, 10, 34, 17, 56, 25, 58, 13, 27, 44, 9, 20, 58, 31, 17, 60, 36, 10, 41, 53, 25, 36, 39, 4, 24, 58, 17, 60, 4, 22, 38, 10, 32, 0, 50, 31, 7, 28, 47, 12, 57, 5, 26, 52, 23, 14, 40, 57, 17, 47, 5, 53, 1, 44, 31, 19, 60, 46, 2, 35, 48, 30, 54, 22, 5, 51, 39, 25, 31, 4, 43, 14, 9, 45, 16, 24, 44, 19, 29, 40, 23, 44, 7, 38, 42, 4, 63, 12, 54, 23, 59, 22, 42, 8, 15, 40, 21, 8, 34, 3, 41, 30, 50 },
+  { 39, 10, 48, 33, 41, 54, 5, 47, 23, 13, 32, 7, 52, 44, 14, 39, 58, 18, 35, 6, 37, 2, 60, 24, 55, 19, 53, 2, 51, 32, 1, 41, 51, 4, 40, 29, 47, 3, 52, 44, 13, 49, 28, 16, 1, 62, 11, 27, 52, 35, 5, 42, 29, 47, 14, 56, 28, 53, 26, 38, 9, 56, 40, 3, 38, 15, 41, 60, 1, 37, 50, 25, 11, 28, 61, 19, 42, 62, 10, 52, 39, 6, 32, 14, 58, 17, 7, 26, 42, 34, 27, 10, 54, 40, 20, 63, 26, 53, 21, 61, 32, 7, 59, 48, 3, 56, 18, 31, 58, 14, 49, 21, 36, 16, 45, 9, 36, 24, 62, 45, 27, 31, 53, 17, 49, 12, 62, 18 },
+  { 28, 59, 21, 58, 2, 16, 38, 9, 62, 3, 56, 41, 10, 31, 50, 4, 32, 52, 12, 63, 23, 46, 33, 31, 4, 48, 25, 43, 14, 23, 47, 11, 22, 55, 14, 60, 23, 37, 11, 39, 23, 2, 45, 56, 31, 43, 19, 55, 16, 46, 21, 51, 11, 33, 44, 2, 41, 18, 5, 52, 23, 44, 17, 60, 27, 49, 11, 32, 44, 10, 54, 2, 56, 33, 8, 38, 13, 29, 36, 16, 24, 63, 27, 51, 21, 43, 56, 12, 49, 3, 59, 48, 1, 15, 46, 7, 36, 2, 47, 11, 50, 27, 37, 13, 33, 8, 51, 46, 1, 34, 28, 40, 3, 33, 60, 29, 47, 1, 35, 11, 59, 42, 2, 60, 26, 46, 6, 35 },
+  { 4, 43, 9, 29, 36, 63, 24, 44, 20, 50, 30, 17, 60, 22, 16, 43, 25, 3, 42, 19, 51, 15, 8, 54, 42, 15, 61, 5, 39, 57, 18, 61, 31, 48, 34, 2, 50, 19, 57, 5, 63, 33, 19, 38, 13, 27, 48, 7, 32, 61, 2, 26, 58, 6, 24, 50, 13, 61, 42, 20, 62, 2, 35, 20, 51, 4, 62, 18, 23, 58, 20, 31, 43, 15, 51, 45, 26, 50, 4, 55, 45, 3, 35, 9, 38, 1, 32, 61, 20, 45, 17, 33, 24, 57, 29, 51, 22, 58, 38, 30, 15, 1, 54, 21, 63, 43, 26, 12, 24, 56, 8, 60, 50, 19, 5, 52, 13, 54, 17, 50, 4, 16, 36, 12, 32, 56, 22, 54 },
+  { 51, 25, 40, 53, 12, 49, 15, 57, 34, 7, 38, 47, 2, 36, 55, 8, 61, 30, 56, 7, 28, 59, 48, 11, 27, 35, 21, 45, 28, 36, 9, 38, 6, 16, 24, 63, 10, 32, 28, 43, 21, 53, 5, 60, 8, 57, 3, 45, 11, 37, 15, 54, 40, 20, 62, 36, 27, 34, 11, 48, 30, 15, 54, 8, 30, 42, 22, 34, 48, 13, 35, 63, 4, 37, 22, 2, 59, 9, 41, 23, 13, 41, 49, 18, 59, 24, 40, 5, 37, 30, 9, 61, 44, 6, 37, 11, 33, 17, 5, 55, 41, 60, 23, 39, 17, 5, 30, 62, 41, 16, 46, 25, 11, 56, 39, 26, 20, 38, 29, 39, 22, 52, 44, 20, 48, 1, 38, 14 },
+  { 15, 33, 2, 18, 44, 6, 27, 0, 32, 61, 25, 12, 58, 28, 40, 20, 47, 13, 34, 43, 38, 1, 23, 62, 40, 0, 51, 10, 63, 3, 52, 26, 44, 30, 45, 6, 41, 54, 0, 51, 12, 30, 46, 24, 49, 22, 40, 33, 63, 23, 43, 30, 9, 47, 0, 17, 54, 7, 57, 3, 37, 47, 24, 46, 13, 55, 7, 52, 2, 42, 6, 26, 49, 18, 60, 34, 16, 57, 33, 20, 61, 30, 8, 54, 14, 46, 12, 53, 16, 55, 38, 13, 22, 53, 18, 59, 46, 27, 43, 19, 32, 10, 45, 6, 49, 36, 52, 2, 20, 55, 6, 39, 32, 15, 44, 3, 58, 10, 63, 6, 56, 30, 7, 58, 9, 40, 19, 63 },
+  { 10, 47, 61, 23, 55, 31, 52, 42, 17, 45, 4, 51, 27, 6, 15, 53, 0, 49, 26, 10, 56, 18, 36, 6, 20, 58, 32, 30, 13, 49, 19, 56, 0, 59, 12, 53, 27, 17, 38, 25, 48, 9, 15, 36, 14, 30, 59, 17, 0, 50, 8, 58, 18, 56, 31, 45, 21, 41, 29, 19, 60, 6, 32, 59, 0, 36, 29, 39, 19, 59, 46, 12, 55, 30, 10, 47, 24, 3, 28, 48, 0, 55, 44, 27, 33, 4, 63, 29, 49, 0, 26, 50, 34, 2, 42, 14, 0, 62, 9, 56, 3, 52, 28, 34, 58, 9, 20, 48, 37, 32, 22, 53, 0, 62, 27, 49, 34, 46, 21, 33, 41, 14, 25, 37, 53, 29, 31, 45 },
+  { 56, 28, 7, 37, 11, 36, 20, 9, 54, 14, 39, 19, 34, 63, 45, 37, 24, 17, 60, 31, 21, 45, 53, 29, 47, 15, 7, 55, 40, 23, 34, 14, 42, 20, 37, 35, 15, 59, 7, 62, 34, 40, 59, 1, 51, 42, 10, 28, 54, 21, 35, 5, 38, 13, 36, 4, 59, 12, 39, 53, 15, 43, 9, 21, 39, 62, 16, 56, 25, 9, 32, 38, 0, 41, 14, 51, 40, 53, 43, 11, 37, 17, 5, 22, 57, 39, 19, 7, 42, 21, 60, 10, 31, 63, 25, 52, 30, 49, 36, 25, 48, 17, 61, 14, 22, 42, 29, 13, 60, 11, 47, 18, 35, 41, 7, 23, 4, 16, 51, 11, 0, 48, 61, 3, 17, 50, 5, 24 },
+  { 0, 42, 21, 49, 60, 3, 57, 40, 29, 48, 23, 56, 42, 11, 22, 5, 59, 39, 4, 50, 3, 41, 12, 57, 25, 50, 44, 18, 4, 46, 7, 62, 33, 50, 4, 56, 21, 32, 43, 18, 3, 23, 55, 34, 20, 4, 53, 38, 12, 46, 29, 52, 25, 61, 23, 51, 26, 46, 1, 34, 25, 57, 28, 51, 26, 11, 50, 3, 44, 28, 53, 21, 57, 27, 62, 6, 31, 19, 8, 63, 26, 59, 36, 47, 15, 29, 50, 25, 35, 47, 18, 41, 4, 48, 8, 40, 12, 23, 6, 44, 13, 40, 1, 31, 55, 0, 61, 43, 4, 50, 26, 58, 9, 53, 24, 61, 42, 55, 31, 43, 57, 20, 34, 27, 43, 8, 59, 39 },
+  { 18, 51, 30, 13, 26, 16, 46, 22, 2, 59, 8, 30, 1, 48, 33, 51, 29, 9, 46, 16, 62, 14, 33, 2, 38, 9, 27, 60, 37, 26, 53, 17, 28, 10, 24, 46, 2, 49, 8, 57, 29, 45, 6, 26, 62, 44, 18, 25, 61, 3, 42, 14, 49, 10, 43, 6, 17, 32, 63, 10, 49, 4, 40, 14, 45, 33, 22, 37, 12, 61, 5, 17, 43, 7, 23, 37, 15, 58, 49, 13, 39, 21, 10, 52, 1, 62, 9, 56, 12, 2, 58, 28, 36, 16, 56, 28, 56, 35, 20, 63, 24, 37, 51, 8, 45, 25, 16, 33, 27, 38, 2, 44, 13, 30, 17, 36, 12, 26, 5, 18, 28, 47, 13, 60, 23, 45, 13, 33 },
+  { 55, 4, 62, 34, 52, 38, 7, 63, 32, 37, 13, 53, 25, 62, 18, 12, 55, 41, 27, 35, 24, 49, 31, 52, 17, 63, 34, 1, 56, 12, 41, 2, 48, 58, 39, 16, 61, 27, 41, 52, 13, 19, 50, 39, 11, 31, 57, 6, 32, 40, 20, 55, 1, 28, 33, 57, 48, 8, 37, 22, 44, 18, 53, 1, 61, 5, 54, 16, 47, 36, 50, 24, 55, 34, 48, 45, 1, 30, 33, 46, 2, 50, 32, 42, 25, 34, 43, 21, 38, 52, 23, 45, 14, 54, 21, 4, 44, 16, 53, 29, 10, 47, 19, 57, 12, 54, 39, 10, 51, 15, 63, 21, 57, 40, 51, 1, 48, 57, 37, 62, 2, 38, 9, 52, 1, 35, 58, 22 },
+  { 36, 46, 10, 42, 1, 27, 43, 15, 50, 21, 45, 16, 41, 3, 35, 44, 20, 1, 57, 11, 55, 7, 43, 8, 22, 42, 13, 46, 21, 39, 31, 60, 22, 5, 29, 44, 11, 35, 20, 4, 36, 58, 32, 15, 47, 2, 36, 48, 16, 60, 8, 35, 44, 63, 16, 2, 40, 26, 55, 14, 58, 35, 24, 31, 19, 42, 31, 58, 1, 29, 10, 40, 2, 19, 12, 54, 22, 61, 7, 24, 56, 5, 28, 16, 54, 3, 15, 58, 6, 30, 8, 62, 1, 43, 31, 47, 7, 59, 1, 38, 58, 4, 34, 27, 38, 5, 31, 59, 7, 46, 30, 3, 34, 6, 28, 59, 20, 8, 32, 15, 53, 24, 55, 31, 19, 49, 11, 26 },
+  { 2, 24, 16, 58, 19, 55, 5, 35, 10, 61, 4, 28, 57, 24, 58, 7, 31, 47, 22, 38, 19, 28, 61, 36, 54, 5, 59, 29, 6, 52, 15, 11, 43, 36, 8, 54, 52, 1, 62, 25, 47, 9, 1, 60, 28, 53, 24, 14, 46, 27, 51, 22, 12, 24, 38, 53, 20, 11, 51, 3, 29, 7, 48, 63, 8, 49, 9, 21, 52, 14, 63, 32, 46, 60, 35, 4, 41, 16, 52, 35, 18, 42, 59, 7, 36, 61, 45, 27, 33, 51, 19, 39, 34, 11, 61, 18, 33, 41, 28, 15, 54, 22, 42, 3, 49, 21, 47, 18, 36, 23, 55, 19, 48, 24, 45, 10, 33, 44, 50, 40, 7, 35, 15, 41, 63, 6, 40, 54 },
+  { 62, 41, 32, 8, 47, 28, 60, 24, 44, 30, 38, 49, 9, 33, 14, 40, 50, 14, 60, 2, 54, 40, 0, 20, 25, 39, 16, 49, 24, 35, 57, 47, 19, 61, 33, 18, 23, 37, 13, 55, 31, 43, 22, 41, 17, 8, 42, 58, 0, 37, 5, 56, 31, 54, 7, 30, 60, 33, 42, 17, 59, 39, 12, 27, 38, 17, 35, 41, 27, 45, 20, 7, 25, 15, 29, 58, 27, 47, 11, 40, 14, 54, 23, 46, 19, 31, 11, 40, 13, 49, 5, 58, 24, 51, 26, 6, 50, 20, 49, 9, 32, 46, 17, 60, 14, 63, 24, 1, 57, 41, 9, 43, 14, 62, 16, 52, 3, 27, 14, 22, 61, 45, 4, 28, 9, 47, 29, 17 },
+  { 5, 50, 12, 53, 38, 18, 11, 51, 0, 55, 17, 6, 47, 54, 19, 63, 5, 26, 34, 45, 13, 30, 47, 58, 10, 48, 32, 3, 62, 9, 26, 0, 25, 14, 50, 3, 47, 30, 42, 16, 6, 63, 12, 49, 33, 55, 21, 10, 34, 63, 18, 41, 3, 47, 19, 43, 0, 49, 8, 28, 46, 20, 52, 0, 56, 24, 60, 3, 59, 5, 39, 57, 48, 52, 9, 38, 3, 21, 26, 60, 0, 32, 12, 38, 4, 48, 53, 0, 60, 15, 29, 44, 18, 10, 38, 57, 13, 60, 2, 26, 62, 7, 50, 29, 35, 8, 40, 53, 28, 12, 60, 33, 38, 5, 37, 29, 60, 39, 56, 0, 30, 18, 50, 34, 59, 25, 14, 44 },
+  { 20, 31, 60, 22, 3, 49, 33, 25, 40, 13, 34, 59, 22, 36, 0, 28, 37, 56, 8, 18, 51, 16, 4, 45, 27, 12, 53, 42, 18, 44, 51, 31, 55, 40, 28, 58, 7, 60, 10, 51, 27, 37, 24, 56, 5, 26, 44, 29, 50, 23, 45, 11, 34, 15, 59, 27, 13, 23, 62, 37, 4, 57, 15, 32, 42, 6, 47, 11, 30, 43, 23, 13, 0, 36, 18, 44, 63, 51, 37, 29, 49, 20, 57, 27, 62, 9, 24, 35, 23, 53, 37, 3, 42, 55, 0, 36, 23, 39, 31, 43, 17, 37, 24, 11, 52, 43, 19, 32, 5, 50, 26, 0, 56, 21, 54, 11, 19, 6, 47, 25, 59, 42, 12, 54, 21, 3, 38, 57 },
+  { 48, 0, 35, 27, 44, 14, 59, 7, 57, 46, 26, 2, 42, 12, 52, 43, 10, 27, 53, 42, 32, 62, 37, 21, 34, 61, 7, 23, 36, 4, 38, 12, 41, 5, 17, 45, 22, 27, 39, 21, 59, 0, 45, 18, 39, 62, 3, 38, 14, 7, 54, 26, 61, 39, 9, 52, 45, 36, 18, 50, 10, 34, 44, 22, 50, 14, 36, 55, 17, 34, 53, 62, 33, 26, 56, 6, 31, 12, 6, 53, 9, 44, 2, 50, 20, 40, 55, 17, 47, 7, 26, 63, 22, 32, 48, 16, 46, 8, 52, 12, 57, 41, 0, 56, 25, 3, 61, 14, 45, 35, 18, 44, 12, 46, 23, 42, 32, 51, 35, 10, 17, 36, 23, 1, 45, 52, 32, 10 },
+  { 37, 15, 43, 8, 63, 39, 21, 31, 16, 37, 19, 62, 30, 46, 17, 60, 21, 48, 1, 23, 6, 25, 11, 56, 1, 40, 30, 58, 15, 54, 21, 59, 9, 63, 35, 56, 11, 51, 2, 46, 34, 14, 53, 7, 30, 11, 51, 19, 60, 40, 30, 1, 24, 50, 20, 32, 3, 56, 5, 25, 31, 13, 61, 2, 29, 60, 25, 20, 51, 2, 27, 8, 18, 42, 10, 45, 21, 34, 43, 17, 62, 29, 41, 14, 34, 6, 30, 43, 2, 57, 33, 13, 45, 12, 27, 62, 4, 55, 21, 35, 5, 27, 45, 33, 16, 47, 30, 54, 22, 10, 51, 27, 63, 7, 49, 1, 58, 22, 15, 43, 53, 7, 57, 39, 27, 12, 61, 24 },
+  { 56, 51, 26, 56, 19, 2, 41, 54, 5, 52, 9, 48, 6, 23, 39, 4, 32, 15, 63, 35, 59, 49, 43, 15, 52, 19, 50, 9, 46, 33, 1, 29, 48, 20, 32, 1, 38, 33, 19, 54, 9, 32, 24, 48, 58, 35, 16, 48, 4, 52, 13, 57, 33, 5, 45, 59, 15, 29, 41, 55, 47, 39, 23, 53, 9, 40, 4, 57, 10, 44, 48, 40, 50, 14, 61, 24, 55, 1, 59, 22, 33, 8, 51, 25, 58, 46, 11, 59, 20, 41, 17, 51, 6, 56, 35, 25, 42, 30, 15, 58, 48, 18, 61, 9, 58, 39, 13, 2, 37, 59, 40, 2, 31, 16, 34, 41, 8, 30, 62, 3, 29, 48, 33, 5, 63, 16, 41, 7 },
+  { 22, 4, 46, 11, 33, 51, 29, 10, 62, 24, 43, 27, 15, 58, 50, 25, 54, 44, 9, 38, 18, 3, 29, 57, 32, 5, 26, 43, 17, 61, 24, 52, 8, 42, 23, 53, 15, 61, 7, 28, 57, 43, 4, 40, 20, 2, 43, 25, 32, 35, 21, 43, 17, 48, 10, 22, 38, 54, 11, 21, 1, 58, 16, 30, 48, 18, 46, 32, 38, 13, 22, 4, 59, 35, 2, 51, 30, 39, 15, 47, 4, 56, 13, 37, 1, 28, 16, 52, 32, 9, 61, 29, 38, 19, 3, 52, 10, 48, 1, 32, 11, 40, 20, 36, 6, 22, 49, 29, 55, 6, 20, 56, 36, 52, 19, 60, 26, 46, 18, 54, 40, 13, 20, 46, 35, 19, 49, 29 },
+  { 61, 17, 34, 53, 23, 6, 48, 35, 20, 40, 1, 56, 36, 29, 11, 34, 7, 41, 14, 30, 55, 20, 46, 8, 24, 38, 63, 2, 37, 10, 45, 14, 34, 49, 6, 13, 44, 25, 49, 41, 21, 12, 61, 15, 54, 29, 63, 12, 56, 8, 49, 2, 62, 36, 28, 61, 0, 25, 41, 63, 35, 8, 44, 6, 37, 62, 7, 21, 63, 28, 55, 31, 16, 24, 41, 19, 9, 57, 27, 36, 18, 42, 31, 62, 22, 55, 38, 4, 27, 47, 1, 40, 14, 54, 43, 20, 60, 23, 38, 63, 25, 51, 2, 53, 26, 63, 10, 42, 17, 34, 47, 25, 13, 5, 44, 11, 55, 2, 38, 27, 6, 60, 52, 25, 9, 55, 1, 40 },
+  { 8, 30, 58, 3, 42, 61, 17, 38, 13, 59, 32, 10, 54, 3, 51, 20, 61, 26, 57, 2, 46, 33, 12, 60, 41, 13, 48, 29, 55, 20, 39, 27, 57, 18, 62, 29, 55, 2, 31, 16, 37, 50, 26, 36, 6, 46, 9, 41, 27, 57, 23, 39, 26, 6, 51, 12, 31, 46, 7, 16, 27, 52, 19, 56, 26, 12, 33, 53, 1, 41, 8, 57, 46, 7, 54, 32, 47, 5, 49, 11, 60, 23, 5, 48, 10, 43, 19, 63, 35, 24, 49, 21, 59, 5, 31, 37, 14, 44, 7, 42, 6, 30, 46, 13, 44, 32, 19, 50, 4, 58, 8, 30, 62, 38, 28, 53, 21, 36, 13, 50, 21, 33, 15, 2, 44, 31, 14, 47 },
+  { 37, 13, 39, 16, 28, 9, 57, 0, 25, 49, 21, 45, 18, 47, 12, 42, 0, 49, 22, 39, 16, 53, 25, 36, 0, 52, 22, 16, 6, 60, 4, 51, 0, 26, 37, 47, 10, 36, 63, 5, 57, 0, 18, 59, 23, 33, 51, 19, 0, 44, 15, 11, 54, 17, 42, 35, 53, 18, 58, 33, 49, 4, 34, 42, 0, 50, 43, 25, 16, 49, 34, 20, 37, 28, 12, 63, 16, 38, 25, 44, 0, 40, 52, 17, 35, 3, 50, 14, 8, 53, 11, 36, 25, 45, 9, 62, 0, 54, 28, 17, 50, 55, 15, 24, 57, 0, 53, 34, 23, 41, 15, 45, 0, 49, 16, 4, 48, 9, 63, 45, 0, 42, 58, 37, 61, 22, 54, 26 },
+  { 0, 50, 21, 47, 54, 36, 27, 45, 52, 4, 34, 15, 63, 29, 37, 59, 17, 31, 6, 61, 28, 5, 48, 18, 59, 27, 34, 56, 44, 31, 35, 12, 41, 59, 16, 3, 40, 20, 50, 22, 30, 40, 52, 10, 45, 3, 59, 22, 37, 61, 29, 46, 31, 58, 2, 22, 9, 43, 3, 39, 14, 61, 24, 54, 15, 29, 11, 60, 39, 17, 5, 61, 0, 44, 50, 3, 31, 14, 58, 21, 54, 28, 15, 45, 60, 26, 33, 58, 44, 22, 60, 2, 57, 34, 49, 27, 18, 34, 21, 59, 29, 4, 36, 41, 8, 39, 28, 11, 62, 26, 53, 20, 35, 24, 59, 32, 29, 39, 24, 31, 57, 23, 11, 28, 5, 36, 11, 59 },
+  { 44, 32, 63, 5, 20, 12, 41, 7, 30, 61, 42, 8, 39, 5, 33, 8, 24, 53, 45, 11, 37, 58, 7, 44, 10, 50, 3, 40, 8, 22, 53, 19, 46, 9, 33, 52, 24, 58, 8, 44, 13, 47, 8, 34, 38, 30, 14, 47, 7, 34, 4, 55, 9, 19, 40, 49, 56, 26, 60, 21, 30, 45, 10, 19, 40, 58, 23, 36, 3, 52, 45, 23, 54, 13, 22, 42, 53, 45, 7, 33, 10, 36, 57, 6, 29, 12, 41, 0, 30, 15, 41, 30, 17, 7, 16, 53, 40, 56, 2, 39, 12, 61, 10, 52, 31, 60, 16, 45, 1, 37, 7, 61, 40, 10, 43, 17, 58, 7, 54, 14, 4, 51, 39, 49, 18, 56, 42, 20 },
+  { 14, 6, 24, 36, 56, 49, 22, 60, 18, 14, 23, 51, 26, 57, 21, 52, 41, 14, 35, 50, 19, 31, 40, 23, 33, 14, 63, 17, 32, 47, 7, 62, 23, 30, 56, 11, 42, 27, 14, 60, 35, 19, 28, 61, 17, 55, 25, 39, 53, 17, 42, 21, 38, 63, 25, 5, 14, 36, 12, 50, 1, 37, 59, 32, 2, 51, 6, 56, 27, 32, 11, 30, 38, 26, 60, 8, 26, 19, 62, 39, 50, 2, 21, 39, 53, 23, 56, 19, 49, 39, 5, 46, 55, 23, 42, 4, 31, 11, 47, 26, 45, 22, 48, 18, 21, 5, 48, 25, 57, 14, 47, 30, 3, 56, 12, 50, 1, 42, 19, 47, 35, 17, 8, 30, 45, 25, 4, 51 },
+  { 28, 58, 43, 1, 31, 8, 33, 2, 44, 55, 32, 1, 60, 12, 46, 27, 4, 62, 23, 1, 56, 13, 62, 2, 54, 36, 25, 51, 1, 57, 26, 42, 3, 49, 17, 38, 1, 48, 31, 4, 54, 3, 50, 24, 1, 49, 5, 63, 13, 27, 52, 1, 48, 13, 45, 33, 52, 30, 46, 20, 55, 28, 6, 48, 24, 38, 20, 47, 14, 62, 48, 9, 58, 4, 36, 30, 56, 1, 34, 12, 18, 63, 25, 48, 4, 16, 37, 7, 62, 10, 52, 28, 13, 50, 36, 63, 24, 51, 15, 58, 8, 33, 1, 38, 56, 35, 42, 9, 33, 51, 22, 18, 48, 32, 27, 37, 23, 61, 33, 11, 59, 29, 62, 1, 53, 10, 60, 33 },
+  { 12, 39, 17, 52, 26, 46, 53, 38, 25, 11, 48, 36, 16, 43, 2, 35, 55, 17, 39, 29, 43, 9, 28, 45, 20, 5, 46, 12, 42, 28, 13, 52, 36, 6, 60, 22, 54, 17, 62, 39, 25, 42, 15, 55, 44, 20, 31, 10, 35, 57, 24, 32, 29, 6, 59, 18, 7, 62, 3, 41, 10, 44, 16, 54, 13, 62, 31, 9, 41, 1, 21, 43, 18, 47, 15, 40, 11, 49, 28, 55, 46, 30, 8, 43, 32, 61, 28, 47, 25, 34, 21, 61, 32, 1, 20, 9, 46, 6, 35, 19, 41, 54, 27, 63, 14, 3, 51, 20, 62, 2, 38, 55, 8, 21, 63, 6, 46, 9, 26, 51, 3, 24, 43, 34, 16, 41, 18, 48 },
+  { 62, 23, 55, 9, 15, 62, 19, 13, 58, 40, 6, 30, 54, 19, 50, 31, 10, 44, 6, 59, 21, 47, 51, 15, 60, 39, 30, 54, 21, 61, 19, 33, 14, 29, 43, 11, 34, 45, 7, 21, 10, 56, 36, 6, 38, 11, 58, 42, 2, 47, 11, 60, 50, 16, 41, 28, 38, 23, 47, 17, 35, 63, 22, 33, 42, 5, 45, 17, 53, 35, 25, 56, 33, 6, 51, 19, 60, 23, 43, 15, 5, 40, 58, 13, 51, 1, 45, 11, 54, 3, 43, 8, 37, 48, 59, 29, 39, 21, 61, 43, 3, 31, 10, 44, 24, 29, 60, 12, 28, 40, 11, 25, 43, 52, 14, 41, 16, 57, 44, 20, 40, 55, 12, 21, 57, 27, 35, 2 },
+  { 37, 6, 31, 42, 40, 4, 29, 50, 0, 20, 63, 28, 9, 58, 14, 24, 63, 26, 48, 16, 34, 4, 32, 38, 23, 11, 58, 4, 37, 9, 45, 5, 63, 48, 26, 57, 2, 28, 32, 51, 46, 29, 13, 62, 27, 46, 28, 18, 50, 15, 40, 4, 19, 34, 54, 0, 53, 9, 26, 58, 28, 5, 49, 0, 57, 27, 19, 60, 29, 8, 59, 12, 37, 63, 24, 46, 3, 37, 6, 52, 26, 32, 20, 36, 9, 22, 59, 18, 35, 51, 14, 57, 17, 24, 12, 44, 56, 0, 30, 13, 59, 20, 49, 17, 54, 43, 6, 34, 46, 17, 58, 36, 0, 34, 29, 54, 25, 2, 36, 15, 60, 6, 37, 46, 4, 50, 9, 45 },
+  { 19, 59, 48, 3, 24, 60, 44, 22, 34, 51, 15, 45, 41, 5, 33, 47, 0, 37, 12, 55, 25, 54, 8, 57, 0, 47, 18, 34, 49, 15, 55, 24, 40, 20, 8, 35, 53, 13, 41, 18, 0, 59, 22, 33, 4, 52, 8, 60, 24, 36, 31, 56, 45, 26, 10, 43, 15, 56, 36, 4, 51, 14, 39, 30, 12, 55, 36, 2, 39, 49, 4, 44, 17, 0, 32, 13, 53, 35, 59, 17, 62, 0, 55, 24, 52, 38, 31, 6, 42, 19, 29, 40, 4, 54, 33, 5, 16, 27, 52, 37, 23, 55, 7, 37, 0, 39, 23, 49, 4, 53, 31, 15, 59, 10, 50, 4, 60, 34, 48, 7, 31, 49, 27, 14, 62, 22, 53, 29 },
+  { 46, 21, 14, 51, 36, 17, 7, 57, 10, 32, 3, 37, 22, 60, 39, 18, 56, 20, 42, 3, 36, 10, 44, 26, 41, 29, 53, 27, 2, 39, 30, 52, 0, 59, 15, 48, 23, 61, 6, 58, 37, 12, 40, 49, 16, 39, 20, 44, 0, 62, 8, 21, 3, 59, 23, 32, 49, 31, 12, 44, 22, 59, 18, 50, 24, 7, 43, 52, 15, 23, 41, 26, 51, 28, 55, 39, 21, 27, 10, 42, 12, 45, 27, 47, 3, 15, 63, 26, 55, 0, 60, 26, 45, 18, 62, 38, 58, 49, 8, 47, 4, 33, 46, 29, 57, 13, 56, 16, 59, 21, 5, 47, 23, 39, 18, 44, 13, 22, 28, 53, 19, 0, 58, 32, 41, 7, 26, 13 },
+  { 0, 56, 34, 28, 11, 55, 31, 47, 26, 41, 56, 13, 53, 28, 11, 49, 7, 52, 32, 61, 50, 22, 63, 17, 13, 56, 7, 19, 43, 62, 10, 21, 37, 32, 43, 4, 38, 19, 44, 25, 31, 54, 5, 23, 61, 30, 53, 12, 35, 22, 43, 53, 37, 48, 7, 62, 20, 2, 61, 41, 8, 34, 47, 9, 63, 34, 28, 10, 55, 33, 14, 57, 7, 47, 9, 61, 4, 49, 31, 50, 21, 38, 8, 16, 57, 44, 33, 5, 49, 36, 12, 50, 7, 34, 10, 25, 2, 22, 36, 15, 26, 61, 18, 9, 22, 46, 32, 8, 27, 37, 44, 30, 55, 3, 62, 24, 38, 56, 5, 45, 38, 24, 43, 10, 19, 54, 39, 61 },
+  { 41, 30, 8, 63, 43, 23, 38, 3, 62, 19, 8, 49, 25, 1, 58, 30, 23, 40, 9, 28, 18, 40, 6, 38, 49, 22, 35, 59, 8, 27, 50, 5, 56, 17, 11, 50, 30, 9, 55, 2, 51, 19, 34, 47, 9, 41, 6, 26, 48, 57, 14, 28, 17, 12, 39, 13, 37, 46, 25, 19, 54, 27, 1, 37, 16, 45, 20, 60, 1, 48, 20, 38, 31, 22, 42, 15, 19, 44, 1, 61, 6, 34, 56, 40, 29, 10, 20, 46, 13, 22, 41, 23, 59, 42, 30, 51, 45, 13, 63, 53, 42, 12, 51, 38, 62, 2, 26, 41, 50, 1, 61, 10, 19, 42, 31, 8, 49, 32, 12, 63, 9, 52, 16, 56, 36, 2, 31, 16 },
+  { 52, 5, 47, 20, 1, 53, 12, 50, 16, 35, 43, 21, 33, 43, 16, 44, 3, 59, 14, 46, 1, 30, 60, 33, 2, 45, 12, 42, 31, 47, 14, 33, 46, 25, 55, 27, 60, 36, 16, 42, 14, 46, 26, 1, 55, 15, 63, 32, 2, 38, 5, 47, 33, 61, 30, 52, 4, 57, 6, 38, 11, 43, 61, 24, 52, 3, 31, 22, 42, 10, 62, 3, 59, 11, 35, 57, 33, 54, 24, 14, 29, 48, 18, 2, 60, 41, 53, 24, 32, 62, 3, 53, 15, 1, 55, 17, 32, 40, 6, 31, 1, 40, 28, 5, 35, 52, 19, 63, 13, 33, 17, 41, 52, 26, 15, 57, 1, 20, 42, 17, 35, 27, 48, 5, 25, 50, 44, 11 },
+  { 35, 25, 38, 57, 33, 17, 40, 6, 59, 27, 54, 5, 61, 10, 52, 26, 36, 19, 51, 35, 57, 48, 11, 20, 54, 25, 61, 16, 1, 58, 24, 61, 3, 39, 7, 47, 1, 22, 49, 28, 63, 10, 58, 32, 17, 36, 45, 19, 51, 29, 59, 10, 50, 1, 23, 42, 18, 29, 51, 21, 56, 32, 14, 5, 40, 58, 47, 13, 54, 35, 29, 45, 18, 52, 26, 2, 38, 8, 46, 36, 58, 11, 52, 35, 17, 28, 1, 58, 9, 39, 17, 28, 37, 48, 20, 9, 57, 24, 50, 19, 58, 16, 48, 25, 43, 11, 35, 6, 45, 24, 56, 4, 36, 7, 47, 35, 52, 28, 59, 30, 2, 61, 21, 33, 63, 12, 18, 59 },
+  { 3, 49, 15, 10, 27, 61, 25, 45, 30, 0, 14, 47, 31, 38, 17, 62, 7, 55, 27, 4, 15, 24, 42, 52, 10, 34, 5, 51, 36, 18, 41, 11, 35, 21, 62, 13, 33, 57, 8, 35, 5, 40, 21, 43, 52, 3, 24, 56, 11, 16, 33, 25, 41, 20, 55, 8, 60, 35, 15, 48, 2, 57, 30, 49, 18, 25, 6, 39, 17, 57, 7, 25, 43, 5, 49, 16, 62, 22, 55, 4, 25, 43, 23, 7, 50, 11, 37, 48, 14, 51, 33, 57, 7, 27, 39, 46, 4, 29, 11, 43, 34, 56, 7, 60, 20, 54, 30, 57, 22, 49, 9, 33, 54, 14, 63, 23, 6, 43, 10, 40, 50, 13, 44, 8, 38, 33, 46, 23 },
+  { 55, 39, 22, 50, 44, 4, 36, 9, 52, 23, 37, 59, 21, 2, 46, 13, 31, 41, 11, 45, 62, 29, 6, 37, 19, 48, 30, 23, 44, 7, 53, 28, 54, 16, 41, 29, 44, 18, 52, 24, 60, 15, 48, 7, 27, 59, 9, 34, 42, 54, 7, 63, 4, 46, 31, 27, 45, 0, 40, 26, 34, 17, 37, 10, 53, 29, 36, 50, 2, 27, 51, 11, 61, 37, 23, 41, 30, 7, 18, 50, 39, 14, 63, 32, 45, 61, 19, 30, 25, 44, 2, 47, 23, 63, 11, 34, 59, 37, 60, 3, 22, 14, 44, 30, 15, 0, 47, 15, 3, 38, 61, 20, 27, 45, 11, 39, 51, 16, 55, 3, 22, 54, 29, 58, 1, 57, 6, 29 },
+  { 9, 17, 60, 2, 34, 56, 20, 62, 39, 12, 49, 6, 29, 56, 34, 48, 0, 58, 22, 38, 18, 43, 56, 0, 63, 14, 55, 3, 59, 31, 15, 45, 0, 49, 6, 58, 3, 38, 12, 45, 0, 37, 29, 57, 13, 39, 30, 49, 0, 23, 44, 36, 16, 57, 13, 54, 11, 24, 63, 9, 53, 7, 62, 42, 0, 59, 15, 23, 63, 34, 40, 16, 32, 0, 53, 12, 48, 28, 59, 33, 0, 53, 9, 27, 3, 22, 54, 5, 56, 9, 61, 13, 42, 14, 52, 19, 0, 21, 47, 27, 53, 36, 3, 50, 39, 58, 25, 40, 53, 28, 12, 50, 0, 59, 32, 2, 21, 34, 26, 46, 37, 7, 18, 47, 24, 14, 53, 42 },
+  { 61, 32, 13, 54, 29, 7, 46, 13, 28, 57, 18, 41, 53, 15, 9, 39, 24, 49, 33, 3, 53, 9, 26, 32, 40, 28, 46, 39, 25, 9, 56, 21, 63, 37, 26, 22, 51, 27, 17, 56, 31, 53, 4, 43, 22, 46, 12, 18, 60, 40, 20, 26, 50, 21, 39, 5, 49, 33, 16, 44, 22, 46, 20, 32, 24, 45, 8, 43, 12, 46, 4, 48, 56, 20, 29, 58, 3, 40, 10, 42, 31, 21, 47, 41, 56, 38, 15, 42, 36, 27, 20, 33, 55, 3, 26, 44, 31, 54, 12, 35, 9, 63, 28, 10, 21, 32, 9, 60, 17, 8, 43, 29, 40, 16, 36, 48, 60, 7, 57, 14, 62, 31, 42, 15, 36, 40, 20, 26 },
+  { 0, 37, 47, 23, 41, 18, 32, 48, 1, 35, 8, 25, 4, 26, 63, 20, 54, 8, 16, 61, 35, 23, 51, 15, 58, 7, 12, 20, 50, 34, 42, 4, 38, 10, 32, 47, 8, 60, 41, 20, 9, 25, 50, 19, 62, 1, 37, 56, 28, 8, 53, 11, 3, 58, 34, 43, 19, 60, 38, 4, 58, 31, 3, 51, 11, 55, 38, 30, 21, 58, 19, 26, 9, 44, 36, 13, 46, 20, 62, 24, 13, 60, 5, 28, 12, 34, 7, 59, 0, 53, 45, 6, 38, 30, 50, 7, 62, 16, 41, 5, 46, 18, 55, 42, 51, 5, 45, 23, 34, 48, 19, 58, 5, 25, 54, 19, 13, 41, 28, 21, 0, 49, 10, 60, 4, 51, 9, 45 },
+  { 19, 28, 6, 58, 10, 51, 4, 22, 55, 42, 60, 45, 34, 51, 42, 5, 30, 45, 27, 40, 13, 47, 4, 49, 21, 38, 60, 29, 2, 57, 17, 27, 52, 19, 61, 14, 30, 34, 2, 44, 63, 33, 11, 35, 16, 51, 25, 6, 14, 47, 31, 61, 37, 29, 18, 8, 52, 2, 28, 54, 13, 41, 15, 62, 35, 18, 2, 60, 6, 33, 41, 61, 31, 6, 56, 17, 34, 50, 6, 52, 44, 35, 16, 51, 59, 24, 48, 18, 31, 40, 16, 49, 21, 60, 17, 39, 10, 49, 32, 57, 24, 39, 1, 25, 18, 62, 37, 12, 56, 1, 37, 11, 52, 44, 9, 30, 47, 4, 51, 40, 55, 25, 34, 27, 56, 30, 32, 54 },
+  { 63, 40, 49, 15, 43, 26, 63, 38, 16, 20, 30, 12, 57, 14, 19, 60, 36, 12, 59, 2, 57, 17, 42, 31, 1, 44, 16, 35, 47, 11, 32, 48, 13, 43, 1, 39, 51, 12, 57, 23, 6, 40, 53, 3, 55, 31, 39, 60, 35, 44, 5, 15, 45, 1, 62, 41, 26, 14, 47, 22, 36, 27, 50, 9, 26, 47, 52, 28, 54, 16, 1, 13, 51, 39, 23, 63, 1, 30, 15, 26, 2, 57, 19, 37, 1, 44, 21, 50, 13, 63, 8, 24, 56, 1, 35, 25, 58, 20, 2, 28, 14, 51, 33, 59, 13, 30, 4, 49, 31, 24, 63, 26, 33, 3, 58, 38, 62, 24, 32, 8, 17, 45, 5, 48, 18, 3, 43, 11 },
+  { 21, 4, 24, 34, 59, 1, 37, 11, 53, 5, 47, 2, 22, 40, 32, 1, 24, 50, 21, 29, 38, 25, 63, 8, 55, 24, 53, 6, 62, 23, 59, 3, 54, 20, 58, 24, 5, 46, 15, 38, 48, 14, 27, 42, 23, 7, 46, 10, 17, 58, 25, 52, 23, 32, 49, 12, 55, 30, 40, 7, 59, 1, 56, 21, 39, 4, 23, 15, 37, 46, 55, 42, 21, 4, 48, 8, 45, 54, 37, 55, 32, 8, 46, 10, 30, 54, 4, 41, 25, 29, 36, 48, 11, 43, 14, 47, 5, 43, 53, 36, 61, 10, 45, 6, 41, 54, 27, 43, 16, 55, 6, 46, 18, 42, 23, 15, 1, 45, 12, 60, 37, 22, 62, 12, 39, 59, 16, 52 },
+  { 47, 35, 56, 7, 19, 46, 31, 50, 33, 24, 61, 35, 50, 7, 53, 44, 55, 6, 46, 10, 52, 5, 21, 43, 36, 10, 18, 41, 26, 37, 8, 29, 40, 36, 9, 49, 34, 26, 61, 21, 7, 59, 18, 62, 29, 54, 20, 32, 51, 0, 40, 10, 55, 6, 20, 36, 9, 61, 5, 51, 44, 19, 33, 43, 13, 57, 40, 63, 8, 24, 29, 10, 60, 34, 27, 40, 25, 18, 10, 42, 21, 49, 26, 62, 38, 12, 33, 61, 5, 57, 2, 19, 54, 28, 62, 22, 38, 31, 16, 7, 22, 47, 29, 17, 35, 8, 20, 51, 2, 40, 22, 50, 13, 61, 28, 53, 35, 20, 56, 30, 2, 53, 14, 41, 23, 34, 8, 31 },
+  { 12, 2, 42, 29, 52, 13, 21, 8, 55, 14, 41, 17, 28, 58, 23, 11, 17, 36, 31, 62, 17, 34, 50, 14, 28, 61, 33, 52, 2, 51, 17, 45, 7, 25, 62, 30, 18, 55, 0, 42, 30, 35, 45, 1, 12, 48, 3, 63, 21, 36, 30, 48, 19, 59, 43, 27, 46, 17, 34, 25, 12, 29, 53, 6, 48, 31, 11, 34, 49, 3, 36, 50, 19, 47, 14, 61, 11, 36, 58, 4, 60, 14, 39, 22, 6, 52, 15, 35, 17, 46, 31, 42, 9, 34, 3, 52, 12, 60, 26, 56, 40, 2, 53, 23, 57, 38, 62, 14, 36, 59, 10, 31, 39, 6, 49, 9, 41, 26, 5, 48, 43, 27, 33, 58, 1, 50, 25, 57 },
+  { 61, 37, 15, 61, 3, 39, 58, 43, 26, 0, 44, 10, 47, 3, 37, 63, 28, 43, 13, 39, 3, 57, 30, 59, 0, 48, 5, 43, 13, 22, 60, 33, 55, 15, 42, 4, 52, 10, 45, 13, 54, 4, 24, 49, 37, 26, 41, 14, 42, 9, 61, 13, 38, 23, 3, 53, 0, 58, 21, 42, 63, 10, 17, 61, 25, 0, 58, 28, 17, 44, 57, 12, 27, 0, 55, 5, 52, 28, 23, 47, 29, 0, 43, 17, 58, 28, 47, 23, 55, 10, 58, 23, 51, 40, 18, 33, 45, 0, 49, 8, 32, 61, 19, 48, 0, 26, 7, 47, 29, 18, 44, 0, 56, 34, 20, 59, 15, 51, 37, 18, 10, 52, 7, 20, 46, 9, 38, 17 },
+  { 6, 27, 48, 23, 45, 29, 5, 18, 38, 62, 27, 56, 20, 32, 15, 9, 48, 0, 54, 22, 45, 20, 7, 41, 23, 39, 19, 27, 58, 31, 44, 0, 12, 50, 23, 56, 20, 39, 32, 59, 16, 52, 33, 9, 57, 22, 6, 58, 28, 50, 24, 2, 56, 35, 16, 45, 32, 38, 15, 54, 2, 38, 46, 22, 35, 45, 20, 5, 52, 25, 7, 35, 59, 32, 22, 43, 38, 3, 51, 16, 34, 53, 32, 50, 3, 40, 8, 43, 0, 39, 27, 4, 14, 61, 8, 55, 15, 41, 20, 44, 27, 13, 39, 11, 46, 42, 54, 33, 4, 52, 23, 61, 14, 25, 43, 2, 33, 11, 63, 29, 61, 17, 40, 55, 22, 62, 28, 44 },
+  { 20, 54, 8, 56, 35, 10, 63, 31, 52, 12, 48, 6, 59, 41, 52, 33, 19, 58, 25, 49, 11, 37, 47, 12, 54, 15, 56, 35, 7, 47, 16, 53, 28, 34, 5, 37, 28, 8, 48, 3, 28, 38, 18, 61, 16, 43, 53, 32, 4, 17, 47, 27, 44, 8, 63, 10, 25, 49, 6, 37, 24, 52, 32, 3, 50, 12, 41, 56, 38, 14, 62, 20, 40, 16, 53, 31, 18, 63, 41, 9, 59, 7, 13, 25, 57, 20, 63, 26, 53, 18, 48, 62, 30, 46, 21, 25, 58, 29, 36, 4, 55, 34, 6, 60, 31, 16, 21, 12, 58, 38, 9, 29, 47, 7, 52, 30, 57, 44, 22, 0, 35, 45, 3, 31, 14, 36, 0, 51 },
+  { 42, 14, 33, 24, 16, 49, 40, 2, 22, 33, 16, 36, 25, 1, 21, 61, 38, 8, 33, 4, 62, 26, 29, 60, 6, 46, 30, 11, 63, 4, 36, 40, 19, 57, 46, 11, 41, 63, 22, 25, 58, 10, 46, 2, 34, 27, 11, 38, 56, 34, 12, 53, 18, 33, 41, 51, 13, 28, 60, 20, 47, 14, 29, 59, 16, 62, 8, 22, 32, 47, 9, 49, 2, 44, 7, 12, 45, 6, 20, 27, 45, 24, 62, 42, 36, 11, 33, 15, 37, 7, 32, 10, 37, 1, 35, 50, 6, 11, 63, 24, 52, 15, 50, 24, 3, 37, 56, 27, 34, 22, 49, 16, 36, 62, 17, 39, 4, 15, 54, 24, 50, 8, 58, 26, 49, 54, 11, 30 },
+  { 4, 59, 41, 1, 53, 12, 25, 45, 59, 7, 51, 39, 54, 14, 46, 4, 27, 53, 16, 44, 18, 51, 1, 32, 25, 2, 50, 40, 20, 54, 24, 9, 62, 2, 27, 60, 1, 17, 36, 50, 6, 40, 30, 55, 41, 19, 49, 1, 21, 60, 40, 5, 62, 1, 22, 30, 57, 4, 43, 31, 1, 55, 40, 7, 27, 37, 30, 54, 1, 19, 42, 30, 56, 26, 62, 49, 24, 57, 37, 56, 2, 39, 16, 5, 30, 55, 3, 49, 60, 23, 56, 44, 17, 52, 13, 42, 28, 48, 18, 45, 9, 37, 21, 41, 58, 10, 48, 1, 63, 5, 41, 57, 2, 24, 12, 48, 27, 42, 32, 46, 13, 38, 19, 34, 5, 41, 25, 60 },
+  { 39, 28, 21, 46, 32, 57, 36, 9, 19, 42, 4, 29, 11, 43, 30, 49, 13, 42, 35, 56, 9, 39, 15, 52, 36, 61, 18, 26, 45, 14, 31, 48, 21, 43, 14, 33, 49, 54, 14, 44, 21, 62, 13, 23, 8, 62, 15, 51, 44, 7, 30, 37, 20, 42, 56, 7, 39, 18, 50, 11, 61, 9, 19, 43, 57, 2, 48, 11, 39, 60, 28, 4, 37, 17, 35, 1, 33, 11, 31, 14, 48, 19, 35, 51, 46, 21, 44, 29, 12, 41, 2, 22, 58, 26, 54, 4, 59, 38, 2, 33, 57, 1, 63, 13, 28, 51, 15, 40, 18, 45, 8, 30, 43, 37, 54, 19, 8, 59, 21, 6, 60, 29, 55, 10, 63, 15, 47, 17 },
+  { 3, 50, 10, 62, 18, 5, 27, 49, 60, 23, 55, 18, 62, 24, 56, 10, 59, 28, 2, 23, 34, 59, 43, 20, 10, 42, 8, 49, 1, 37, 57, 6, 51, 29, 53, 7, 23, 31, 5, 32, 51, 0, 35, 54, 45, 31, 5, 26, 36, 24, 55, 15, 48, 29, 14, 48, 26, 60, 21, 41, 36, 26, 50, 33, 14, 44, 17, 24, 52, 15, 46, 23, 54, 6, 47, 21, 60, 50, 4, 53, 29, 61, 8, 23, 1, 60, 19, 6, 53, 16, 47, 34, 6, 39, 16, 31, 12, 20, 53, 22, 30, 43, 25, 46, 35, 6, 44, 32, 53, 26, 55, 19, 11, 59, 5, 33, 51, 1, 35, 53, 25, 3, 42, 23, 44, 32, 7, 53 },
+  { 22, 44, 37, 6, 26, 51, 38, 0, 34, 13, 31, 46, 3, 37, 6, 19, 40, 21, 47, 63, 12, 5, 29, 55, 22, 58, 34, 28, 60, 22, 11, 41, 17, 38, 9, 44, 59, 39, 56, 19, 11, 47, 25, 15, 3, 39, 57, 17, 61, 11, 46, 3, 58, 9, 54, 35, 2, 34, 8, 45, 15, 56, 5, 23, 53, 33, 63, 35, 4, 59, 10, 51, 13, 61, 29, 41, 15, 25, 43, 19, 40, 10, 54, 33, 41, 12, 38, 51, 31, 26, 61, 9, 30, 45, 24, 62, 49, 40, 10, 61, 14, 49, 5, 17, 54, 20, 60, 23, 3, 13, 35, 50, 32, 23, 46, 27, 38, 63, 16, 12, 39, 48, 18, 51, 1, 27, 56, 35 },
+  { 63, 15, 30, 55, 43, 14, 57, 17, 53, 44, 7, 48, 26, 50, 32, 60, 0, 53, 14, 31, 50, 24, 46, 0, 38, 13, 4, 52, 16, 45, 30, 59, 0, 25, 55, 35, 16, 10, 26, 42, 58, 29, 60, 38, 50, 22, 28, 47, 0, 50, 28, 19, 33, 39, 11, 44, 16, 52, 24, 59, 3, 38, 27, 51, 0, 21, 7, 42, 26, 34, 21, 40, 33, 18, 39, 3, 54, 38, 8, 59, 0, 44, 27, 15, 58, 28, 57, 9, 43, 0, 36, 50, 20, 59, 8, 34, 0, 27, 47, 7, 36, 19, 56, 32, 0, 38, 11, 29, 62, 47, 6, 61, 0, 41, 14, 56, 10, 23, 45, 31, 57, 8, 36, 13, 58, 38, 11, 19 },
+  { 0, 34, 12, 47, 21, 2, 40, 30, 11, 25, 61, 20, 40, 15, 35, 22, 45, 36, 7, 41, 17, 57, 9, 48, 32, 62, 44, 24, 35, 3, 54, 13, 33, 63, 19, 4, 48, 22, 62, 2, 37, 8, 33, 6, 20, 52, 9, 32, 43, 13, 39, 63, 25, 4, 49, 23, 62, 32, 9, 30, 48, 18, 63, 12, 46, 29, 58, 13, 48, 8, 57, 31, 0, 51, 9, 58, 12, 22, 47, 29, 35, 22, 49, 5, 46, 4, 34, 20, 63, 24, 56, 11, 41, 3, 51, 19, 56, 35, 17, 58, 28, 42, 9, 45, 59, 26, 51, 42, 17, 36, 25, 15, 53, 21, 44, 3, 30, 55, 5, 50, 21, 28, 61, 32, 6, 49, 28, 46 },
+  { 58, 42, 60, 4, 31, 59, 22, 63, 35, 38, 9, 54, 1, 57, 8, 51, 16, 58, 27, 53, 3, 38, 30, 15, 27, 6, 19, 56, 10, 50, 21, 36, 47, 5, 43, 28, 51, 32, 13, 46, 18, 54, 16, 43, 63, 12, 36, 59, 22, 34, 5, 52, 17, 59, 27, 41, 0, 19, 55, 37, 13, 43, 6, 34, 41, 10, 36, 55, 19, 44, 3, 16, 58, 27, 49, 25, 32, 62, 17, 55, 13, 63, 18, 52, 25, 37, 17, 48, 13, 32, 5, 46, 28, 37, 14, 43, 25, 5, 51, 39, 3, 52, 33, 22, 8, 40, 12, 4, 57, 9, 46, 39, 28, 58, 13, 62, 17, 42, 19, 36, 0, 47, 16, 43, 24, 21, 54, 13 },
+  { 25, 9, 23, 50, 36, 8, 45, 14, 3, 51, 16, 28, 44, 12, 42, 29, 4, 26, 10, 47, 22, 61, 18, 54, 51, 39, 46, 13, 41, 26, 58, 7, 18, 39, 12, 57, 15, 1, 52, 27, 41, 23, 48, 1, 27, 45, 18, 2, 57, 26, 55, 8, 43, 31, 6, 58, 14, 51, 40, 5, 61, 31, 24, 54, 17, 60, 22, 1, 39, 30, 53, 45, 36, 13, 43, 5, 45, 2, 37, 6, 34, 42, 2, 39, 10, 62, 7, 54, 40, 18, 60, 15, 52, 21, 63, 8, 55, 46, 15, 30, 23, 13, 62, 16, 50, 24, 58, 31, 48, 21, 34, 2, 49, 7, 31, 37, 26, 48, 9, 61, 40, 11, 52, 2, 60, 40, 4, 37 },
+  { 52, 28, 39, 16, 54, 19, 29, 55, 42, 20, 58, 33, 24, 63, 18, 55, 39, 62, 43, 34, 12, 40, 6, 35, 2, 25, 8, 62, 34, 1, 31, 42, 61, 27, 53, 24, 40, 61, 34, 8, 59, 4, 30, 56, 40, 6, 53, 42, 10, 48, 16, 37, 12, 46, 21, 36, 47, 11, 28, 45, 22, 10, 57, 2, 49, 31, 14, 44, 61, 11, 25, 6, 23, 63, 18, 36, 28, 56, 20, 51, 11, 48, 27, 56, 32, 22, 45, 30, 2, 42, 27, 39, 1, 44, 23, 31, 38, 22, 11, 61, 43, 54, 4, 47, 35, 2, 44, 16, 28, 54, 12, 62, 18, 43, 10, 52, 1, 58, 33, 15, 29, 56, 20, 34, 9, 30, 48, 17 },
+  { 46, 2, 56, 11, 41, 1, 49, 6, 27, 47, 2, 48, 5, 32, 37, 3, 13, 19, 32, 1, 55, 28, 60, 17, 43, 59, 32, 20, 49, 16, 55, 23, 14, 46, 2, 36, 6, 30, 20, 49, 12, 47, 35, 14, 21, 60, 29, 14, 35, 24, 46, 1, 56, 29, 53, 8, 33, 23, 56, 1, 35, 46, 20, 39, 26, 4, 53, 28, 17, 38, 60, 34, 48, 9, 55, 15, 46, 7, 41, 31, 60, 24, 16, 36, 1, 59, 19, 52, 35, 6, 55, 11, 59, 33, 7, 57, 4, 29, 48, 1, 19, 26, 37, 30, 18, 63, 37, 6, 59, 1, 40, 24, 56, 33, 46, 22, 35, 7, 24, 53, 39, 5, 26, 45, 55, 18, 62, 7 },
+  { 20, 60, 29, 34, 20, 62, 33, 52, 10, 36, 13, 60, 41, 21, 50, 27, 56, 49, 8, 51, 21, 45, 11, 48, 8, 23, 53, 3, 29, 44, 5, 52, 9, 32, 50, 17, 43, 56, 3, 38, 24, 10, 62, 25, 51, 9, 33, 49, 61, 7, 30, 62, 22, 19, 2, 42, 63, 5, 49, 18, 60, 15, 52, 7, 43, 56, 23, 50, 5, 50, 2, 20, 41, 30, 1, 52, 22, 61, 14, 26, 3, 43, 53, 7, 47, 28, 11, 14, 23, 58, 33, 25, 47, 13, 50, 17, 40, 54, 34, 60, 41, 6, 59, 14, 50, 7, 25, 55, 20, 42, 51, 8, 27, 4, 16, 60, 28, 50, 44, 3, 22, 49, 63, 12, 33, 1, 43, 31 },
+  { 36, 5, 46, 8, 44, 24, 13, 39, 25, 57, 31, 18, 8, 52, 10, 45, 6, 30, 36, 24, 63, 4, 33, 26, 57, 40, 15, 56, 37, 12, 40, 25, 37, 58, 11, 63, 21, 45, 16, 60, 31, 53, 18, 33, 3, 45, 23, 0, 20, 54, 40, 15, 50, 38, 60, 16, 25, 42, 29, 38, 7, 41, 25, 62, 18, 33, 8, 35, 42, 16, 32, 56, 12, 39, 59, 19, 34, 9, 49, 38, 57, 12, 21, 50, 14, 40, 61, 44, 50, 9, 49, 19, 3, 29, 35, 62, 12, 24, 7, 18, 52, 32, 10, 46, 21, 41, 32, 11, 36, 29, 14, 34, 60, 38, 54, 11, 41, 14, 19, 57, 32, 16, 7, 41, 51, 25, 14, 57 },
+  { 53, 18, 26, 50, 15, 58, 4, 63, 17, 43, 7, 40, 61, 35, 15, 41, 23, 60, 16, 38, 14, 42, 19, 50, 0, 31, 10, 46, 27, 63, 18, 60, 0, 20, 29, 39, 8, 26, 37, 5, 42, 0, 44, 39, 57, 17, 58, 41, 28, 37, 4, 32, 9, 44, 12, 31, 54, 10, 59, 14, 27, 53, 12, 36, 0, 47, 13, 63, 21, 58, 10, 24, 50, 27, 4, 26, 44, 53, 31, 0, 18, 42, 29, 33, 57, 4, 32, 26, 0, 38, 16, 61, 41, 53, 20, 0, 42, 44, 49, 27, 10, 56, 39, 0, 57, 15, 53, 49, 3, 61, 22, 47, 17, 5, 49, 26, 2, 63, 39, 10, 47, 27, 37, 23, 4, 59, 38, 10 },
+  { 23, 39, 61, 3, 37, 28, 48, 31, 0, 34, 51, 23, 2, 26, 58, 0, 53, 11, 46, 1, 57, 29, 52, 14, 37, 61, 21, 35, 2, 49, 7, 34, 47, 55, 4, 33, 54, 13, 58, 52, 19, 50, 22, 7, 13, 29, 36, 11, 51, 17, 60, 25, 55, 4, 34, 51, 0, 35, 20, 48, 32, 3, 51, 30, 59, 28, 40, 3, 46, 29, 54, 43, 7, 62, 47, 11, 39, 4, 23, 46, 55, 8, 63, 5, 25, 37, 18, 46, 21, 56, 31, 5, 36, 8, 45, 58, 26, 15, 2, 36, 47, 21, 29, 44, 25, 34, 3, 27, 43, 10, 52, 0, 45, 30, 24, 36, 43, 18, 34, 59, 0, 52, 61, 15, 44, 19, 30, 49 },
+  { 0, 27, 12, 43, 54, 9, 22, 53, 21, 46, 15, 55, 29, 47, 20, 33, 39, 28, 59, 35, 9, 44, 5, 24, 47, 7, 52, 17, 56, 22, 30, 42, 14, 26, 45, 18, 49, 1, 24, 34, 11, 27, 55, 32, 61, 47, 2, 56, 6, 44, 13, 47, 36, 27, 58, 22, 16, 47, 40, 4, 57, 38, 21, 45, 16, 9, 56, 26, 11, 38, 0, 22, 36, 17, 33, 57, 16, 30, 62, 15, 35, 40, 20, 45, 59, 10, 54, 8, 63, 13, 52, 27, 22, 57, 28, 12, 32, 51, 55, 22, 63, 4, 16, 54, 12, 62, 45, 19, 58, 13, 32, 40, 20, 56, 7, 57, 9, 54, 6, 29, 42, 21, 8, 55, 35, 47, 6, 41 },
+  { 56, 33, 58, 32, 19, 35, 42, 6, 59, 11, 38, 5, 49, 12, 62, 7, 52, 17, 5, 25, 54, 20, 61, 31, 54, 27, 41, 11, 44, 5, 59, 12, 36, 51, 10, 61, 28, 41, 48, 9, 43, 63, 5, 40, 20, 8, 49, 26, 34, 21, 58, 1, 18, 45, 7, 39, 61, 26, 8, 50, 23, 10, 63, 5, 55, 37, 19, 49, 52, 15, 59, 47, 13, 54, 1, 25, 42, 58, 10, 48, 3, 27, 50, 1, 17, 48, 34, 41, 16, 40, 2, 45, 10, 39, 17, 61, 5, 38, 19, 9, 41, 31, 60, 38, 5, 23, 36, 8, 30, 55, 24, 63, 12, 48, 14, 51, 31, 20, 45, 25, 12, 50, 32, 2, 28, 11, 62, 14 },
+  { 44, 16, 7, 48, 1, 62, 16, 50, 27, 33, 61, 25, 17, 44, 31, 14, 22, 43, 32, 48, 18, 40, 8, 36, 3, 16, 33, 62, 23, 38, 25, 53, 2, 21, 41, 6, 22, 15, 59, 29, 16, 37, 26, 15, 52, 42, 23, 15, 54, 39, 10, 30, 53, 11, 49, 24, 2, 43, 55, 17, 34, 44, 15, 31, 24, 44, 2, 32, 7, 35, 25, 5, 40, 45, 29, 51, 6, 21, 37, 52, 24, 60, 13, 31, 53, 23, 2, 28, 49, 24, 31, 60, 20, 51, 1, 34, 48, 14, 59, 33, 50, 1, 18, 33, 48, 60, 17, 51, 39, 6, 38, 2, 35, 29, 40, 23, 1, 62, 15, 53, 37, 17, 46, 57, 40, 51, 24, 22 },
+  { 5, 37, 52, 24, 45, 13, 40, 3, 45, 9, 19, 42, 56, 4, 37, 46, 56, 2, 63, 11, 51, 1, 49, 13, 59, 45, 39, 1, 48, 15, 58, 9, 46, 31, 54, 35, 57, 38, 3, 46, 56, 4, 47, 57, 1, 30, 38, 63, 3, 46, 28, 63, 41, 14, 33, 62, 19, 32, 13, 28, 61, 1, 53, 42, 11, 60, 22, 62, 27, 42, 61, 31, 19, 8, 61, 12, 32, 55, 2, 18, 33, 12, 43, 36, 9, 62, 30, 55, 6, 58, 35, 7, 43, 29, 54, 23, 43, 30, 3, 25, 11, 45, 52, 28, 7, 14, 42, 1, 22, 50, 16, 53, 19, 59, 4, 46, 33, 41, 4, 35, 58, 5, 26, 13, 20, 2, 34, 54 },
+  { 30, 63, 21, 10, 26, 55, 29, 59, 23, 39, 53, 1, 36, 24, 59, 27, 10, 34, 23, 38, 30, 60, 22, 42, 28, 19, 9, 57, 30, 19, 43, 33, 13, 63, 3, 19, 11, 50, 31, 20, 14, 34, 10, 35, 17, 59, 7, 31, 19, 25, 50, 5, 20, 57, 29, 6, 52, 41, 4, 46, 20, 37, 26, 17, 49, 6, 39, 18, 53, 14, 3, 49, 57, 23, 34, 48, 14, 41, 28, 38, 56, 6, 58, 25, 39, 19, 43, 15, 37, 11, 47, 18, 53, 4, 37, 9, 62, 21, 53, 40, 57, 24, 13, 40, 56, 26, 47, 31, 59, 25, 45, 27, 10, 43, 21, 61, 13, 27, 48, 9, 23, 43, 31, 62, 38, 59, 9, 47 },
+  { 25, 4, 40, 60, 34, 6, 18, 36, 8, 57, 12, 30, 49, 14, 6, 54, 41, 16, 50, 6, 43, 15, 34, 4, 53, 24, 50, 35, 4, 51, 7, 55, 28, 24, 39, 44, 60, 7, 25, 62, 42, 53, 24, 61, 28, 45, 52, 12, 48, 37, 9, 35, 43, 3, 37, 48, 12, 58, 30, 52, 9, 59, 6, 57, 33, 29, 48, 4, 37, 45, 20, 34, 10, 39, 0, 60, 22, 45, 8, 63, 21, 42, 14, 49, 3, 56, 11, 46, 21, 61, 0, 42, 25, 13, 63, 17, 36, 8, 46, 16, 6, 35, 63, 0, 21, 37, 4, 57, 9, 34, 5, 61, 48, 32, 8, 37, 54, 17, 56, 30, 60, 0, 50, 16, 7, 29, 42, 17 },
+  { 32, 50, 15, 48, 2, 43, 52, 25, 47, 16, 32, 63, 21, 52, 40, 19, 0, 61, 29, 58, 20, 56, 26, 46, 12, 55, 6, 22, 62, 32, 17, 40, 0, 49, 34, 8, 27, 32, 48, 0, 21, 39, 5, 44, 12, 6, 22, 40, 0, 57, 16, 60, 23, 17, 54, 22, 36, 15, 24, 39, 19, 34, 47, 23, 0, 54, 13, 51, 24, 9, 55, 16, 52, 27, 44, 20, 4, 54, 26, 49, 0, 30, 46, 16, 29, 51, 34, 4, 52, 28, 33, 15, 57, 39, 26, 49, 0, 56, 27, 31, 48, 20, 43, 29, 53, 11, 46, 19, 41, 13, 55, 18, 0, 57, 26, 51, 2, 44, 6, 38, 14, 40, 22, 45, 36, 53, 3, 57 },
+  { 44, 12, 37, 28, 22, 57, 11, 38, 0, 51, 9, 41, 4, 29, 11, 47, 33, 45, 12, 26, 3, 36, 9, 63, 31, 16, 38, 44, 14, 47, 25, 61, 20, 58, 15, 47, 17, 57, 13, 36, 9, 51, 18, 29, 50, 36, 54, 20, 61, 27, 32, 13, 53, 44, 9, 27, 0, 63, 45, 2, 56, 10, 14, 43, 41, 28, 58, 11, 35, 60, 30, 41, 6, 63, 11, 51, 37, 32, 15, 10, 35, 53, 5, 61, 22, 7, 26, 59, 23, 9, 44, 48, 21, 3, 51, 32, 24, 41, 12, 61, 2, 55, 9, 15, 35, 58, 28, 15, 62, 30, 37, 23, 42, 29, 11, 17, 35, 24, 63, 20, 52, 28, 8, 55, 11, 23, 47, 19 },
+  { 0, 56, 8, 53, 14, 31, 61, 20, 55, 28, 62, 18, 35, 60, 25, 57, 7, 23, 39, 54, 47, 17, 43, 0, 40, 59, 29, 2, 56, 10, 37, 5, 43, 11, 29, 52, 1, 23, 54, 41, 59, 30, 55, 1, 62, 15, 33, 4, 43, 10, 47, 39, 1, 31, 40, 60, 49, 33, 7, 55, 26, 50, 31, 61, 8, 18, 21, 32, 44, 1, 25, 47, 18, 36, 30, 23, 59, 7, 40, 59, 27, 19, 38, 32, 44, 54, 40, 17, 38, 60, 27, 6, 35, 55, 10, 14, 44, 5, 50, 17, 38, 26, 42, 50, 18, 3, 44, 52, 2, 49, 7, 52, 15, 46, 62, 39, 55, 10, 31, 48, 3, 58, 33, 18, 61, 34, 13, 59 },
+  { 39, 27, 63, 20, 35, 41, 4, 45, 26, 5, 38, 13, 44, 2, 50, 17, 37, 52, 2, 13, 28, 58, 24, 51, 21, 8, 34, 48, 27, 42, 18, 51, 31, 56, 5, 36, 38, 44, 4, 17, 26, 11, 38, 23, 42, 8, 56, 39, 24, 51, 5, 56, 21, 59, 14, 6, 18, 42, 22, 35, 16, 37, 3, 25, 39, 46, 63, 5, 50, 17, 58, 8, 55, 3, 50, 12, 43, 17, 47, 2, 51, 9, 62, 12, 1, 35, 13, 50, 1, 37, 12, 51, 19, 29, 46, 59, 22, 58, 33, 45, 22, 60, 10, 32, 61, 39, 8, 33, 25, 36, 20, 60, 38, 4, 21, 5, 28, 45, 12, 18, 42, 11, 49, 1, 27, 40, 6, 30 },
+  { 24, 16, 42, 1, 50, 10, 48, 17, 33, 43, 24, 48, 21, 55, 31, 42, 10, 21, 63, 35, 49, 6, 33, 13, 41, 53, 10, 20, 60, 6, 53, 26, 12, 41, 22, 60, 14, 28, 63, 33, 49, 3, 45, 16, 48, 26, 14, 46, 18, 30, 35, 26, 8, 50, 29, 51, 25, 57, 12, 47, 53, 9, 62, 20, 54, 2, 36, 15, 40, 28, 33, 13, 38, 24, 46, 1, 29, 56, 33, 20, 44, 24, 41, 26, 57, 20, 63, 8, 30, 55, 5, 41, 62, 8, 34, 2, 37, 10, 19, 6, 37, 1, 53, 23, 5, 27, 58, 22, 43, 12, 50, 26, 9, 34, 54, 32, 49, 1, 59, 37, 22, 46, 25, 36, 51, 15, 54, 46 },
+  { 52, 7, 45, 33, 26, 58, 14, 60, 7, 54, 3, 58, 8, 34, 14, 5, 59, 30, 18, 44, 8, 22, 48, 62, 3, 26, 55, 38, 23, 16, 39, 1, 62, 24, 49, 9, 53, 19, 46, 7, 19, 60, 31, 58, 2, 34, 53, 7, 59, 2, 62, 42, 46, 19, 36, 11, 44, 4, 38, 28, 1, 43, 32, 51, 12, 29, 56, 22, 52, 2, 62, 49, 22, 60, 14, 35, 63, 5, 25, 57, 14, 53, 4, 46, 18, 31, 42, 22, 47, 20, 58, 31, 16, 43, 23, 54, 30, 42, 52, 57, 29, 49, 30, 13, 45, 48, 16, 55, 6, 63, 1, 44, 14, 58, 19, 47, 15, 24, 51, 34, 6, 55, 5, 63, 20, 41, 21, 9 },
+  { 30, 62, 18, 55, 5, 23, 39, 29, 49, 30, 15, 36, 28, 46, 60, 25, 39, 46, 4, 32, 61, 40, 15, 30, 36, 45, 14, 2, 49, 33, 57, 45, 18, 32, 3, 45, 30, 2, 35, 52, 40, 27, 13, 21, 38, 63, 20, 28, 37, 23, 16, 10, 13, 55, 2, 62, 21, 32, 60, 17, 58, 23, 5, 40, 16, 48, 7, 45, 10, 26, 43, 19, 6, 31, 52, 21, 39, 16, 48, 9, 37, 28, 36, 55, 7, 48, 3, 59, 15, 45, 25, 1, 53, 13, 47, 7, 62, 15, 4, 25, 12, 41, 18, 60, 38, 11, 34, 19, 39, 31, 29, 56, 23, 42, 3, 27, 60, 41, 8, 16, 61, 29, 43, 9, 32, 2, 60, 34 },
+  { 3, 38, 13, 37, 52, 44, 2, 19, 12, 42, 63, 19, 40, 1, 20, 50, 12, 55, 15, 56, 27, 1, 54, 11, 57, 18, 32, 63, 44, 4, 29, 13, 37, 61, 35, 16, 42, 57, 12, 22, 6, 55, 43, 10, 50, 5, 44, 11, 48, 52, 34, 58, 28, 41, 38, 30, 7, 52, 11, 49, 30, 14, 45, 27, 59, 34, 21, 38, 32, 58, 11, 36, 56, 42, 9, 41, 3, 54, 31, 42, 0, 60, 16, 11, 39, 24, 52, 33, 6, 36, 10, 40, 32, 60, 26, 20, 39, 28, 47, 34, 63, 8, 54, 3, 24, 56, 0, 51, 13, 47, 16, 40, 7, 35, 52, 11, 36, 4, 57, 30, 39, 13, 18, 50, 58, 28, 12, 48 },
+  { 57, 24, 49, 21, 10, 31, 61, 36, 56, 0, 22, 53, 11, 56, 32, 7, 36, 27, 41, 9, 46, 19, 34, 42, 25, 7, 50, 9, 28, 21, 54, 8, 50, 7, 27, 59, 10, 25, 48, 62, 37, 0, 33, 58, 25, 18, 32, 61, 0, 15, 45, 5, 50, 3, 23, 55, 47, 17, 40, 6, 60, 34, 53, 8, 41, 0, 61, 13, 54, 4, 46, 28, 0, 17, 48, 27, 58, 13, 23, 61, 33, 21, 50, 30, 62, 8, 14, 29, 56, 27, 61, 49, 17, 2, 44, 11, 51, 0, 59, 17, 40, 20, 32, 47, 36, 21, 42, 28, 60, 4, 54, 10, 59, 17, 30, 62, 21, 43, 26, 48, 0, 56, 36, 25, 8, 44, 39, 17 },
+  { 10, 42, 4, 59, 27, 47, 8, 23, 51, 32, 45, 6, 37, 26, 48, 43, 62, 0, 21, 53, 38, 12, 51, 5, 60, 47, 24, 37, 59, 15, 35, 47, 22, 55, 0, 50, 21, 40, 6, 29, 15, 52, 24, 8, 41, 55, 13, 29, 40, 56, 24, 31, 19, 33, 61, 15, 0, 35, 24, 42, 21, 2, 19, 57, 24, 15, 30, 50, 20, 25, 40, 16, 57, 34, 61, 8, 29, 45, 6, 49, 11, 47, 2, 44, 19, 57, 38, 50, 12, 42, 21, 4, 35, 52, 28, 56, 23, 36, 13, 45, 4, 52, 27, 14, 6, 62, 9, 45, 21, 37, 25, 46, 33, 49, 0, 44, 7, 53, 13, 19, 53, 31, 3, 47, 15, 56, 22, 51 },
+  { 35, 28, 53, 32, 1, 16, 54, 40, 9, 17, 25, 58, 14, 59, 3, 22, 16, 51, 31, 5, 23, 58, 28, 17, 35, 20, 0, 42, 11, 52, 3, 31, 41, 17, 43, 13, 32, 54, 18, 60, 32, 45, 17, 49, 2, 36, 51, 22, 7, 36, 9, 63, 48, 12, 46, 26, 43, 28, 63, 13, 48, 37, 51, 33, 5, 47, 55, 9, 42, 63, 7, 51, 24, 12, 37, 19, 55, 34, 18, 38, 15, 28, 54, 34, 5, 43, 22, 0, 48, 14, 54, 24, 58, 9, 38, 5, 32, 55, 21, 30, 49, 9, 59, 43, 30, 51, 35, 26, 7, 53, 2, 22, 14, 27, 57, 18, 38, 24, 33, 45, 10, 41, 20, 60, 37, 5, 32, 0 },
+  { 63, 19, 15, 40, 62, 35, 14, 28, 46, 61, 4, 49, 35, 10, 29, 54, 33, 8, 45, 62, 37, 1, 43, 55, 10, 52, 61, 30, 19, 40, 25, 62, 11, 38, 27, 58, 36, 3, 46, 8, 39, 4, 62, 28, 47, 20, 4, 54, 47, 27, 43, 1, 21, 38, 8, 58, 10, 54, 4, 56, 9, 26, 12, 39, 60, 27, 18, 37, 1, 31, 35, 5, 45, 50, 2, 43, 26, 1, 59, 23, 56, 40, 7, 26, 58, 17, 32, 63, 25, 39, 7, 31, 45, 19, 63, 15, 48, 8, 37, 61, 16, 34, 1, 56, 18, 3, 15, 58, 49, 32, 63, 41, 55, 5, 40, 22, 50, 6, 59, 2, 63, 23, 52, 11, 26, 61, 44, 23 },
+  { 11, 56, 46, 6, 22, 43, 58, 3, 34, 21, 38, 30, 18, 44, 52, 13, 41, 57, 17, 28, 14, 49, 25, 7, 33, 39, 26, 6, 56, 48, 1, 20, 56, 5, 46, 9, 19, 51, 30, 25, 56, 21, 35, 14, 57, 42, 16, 33, 10, 57, 17, 59, 41, 25, 53, 37, 20, 40, 30, 18, 31, 62, 44, 22, 3, 44, 11, 48, 23, 53, 18, 60, 29, 22, 62, 15, 53, 47, 10, 41, 3, 19, 52, 36, 13, 46, 10, 35, 3, 61, 41, 16, 1, 50, 26, 42, 18, 46, 2, 25, 54, 20, 39, 23, 47, 31, 41, 12, 38, 17, 8, 19, 31, 48, 12, 61, 9, 54, 29, 35, 15, 38, 6, 43, 34, 14, 7, 47 },
+  { 39, 2, 33, 26, 53, 8, 18, 50, 41, 12, 53, 1, 63, 24, 19, 39, 2, 24, 47, 10, 60, 38, 19, 63, 48, 4, 15, 45, 32, 14, 60, 36, 29, 53, 23, 63, 34, 12, 61, 1, 43, 11, 53, 30, 1, 26, 60, 45, 23, 39, 3, 29, 12, 50, 4, 16, 51, 3, 45, 36, 50, 1, 16, 54, 35, 14, 57, 30, 58, 9, 46, 14, 41, 10, 32, 38, 4, 30, 21, 51, 32, 63, 25, 1, 60, 27, 53, 18, 51, 22, 28, 55, 34, 12, 40, 3, 60, 29, 57, 41, 6, 44, 11, 53, 8, 61, 24, 57, 1, 28, 44, 59, 36, 3, 34, 25, 41, 31, 16, 44, 22, 47, 28, 58, 1, 49, 54, 29 },
+  { 58, 25, 50, 13, 38, 30, 60, 24, 6, 57, 27, 42, 9, 45, 6, 61, 30, 50, 4, 34, 29, 3, 46, 13, 22, 42, 58, 28, 9, 39, 23, 44, 7, 15, 44, 2, 40, 15, 47, 41, 23, 37, 7, 59, 38, 11, 34, 6, 62, 14, 52, 35, 55, 19, 32, 61, 33, 24, 57, 6, 22, 59, 29, 7, 49, 25, 40, 3, 17, 39, 27, 52, 0, 55, 16, 57, 24, 61, 36, 6, 29, 12, 48, 39, 20, 44, 6, 40, 33, 5, 48, 10, 57, 36, 22, 51, 33, 9, 24, 12, 62, 29, 50, 35, 14, 43, 5, 33, 47, 52, 13, 23, 10, 51, 56, 16, 46, 1, 49, 4, 61, 9, 52, 18, 31, 21, 36, 17 },
+  { 19, 42, 9, 48, 2, 44, 11, 37, 48, 20, 33, 16, 55, 35, 49, 15, 37, 20, 59, 16, 53, 22, 56, 31, 50, 11, 34, 54, 16, 51, 4, 49, 33, 53, 21, 28, 56, 24, 31, 9, 52, 16, 48, 24, 44, 13, 51, 20, 31, 49, 18, 6, 34, 2, 44, 14, 47, 8, 15, 43, 13, 41, 33, 52, 20, 61, 7, 51, 34, 62, 4, 20, 36, 33, 43, 8, 46, 13, 53, 17, 45, 42, 9, 31, 52, 11, 30, 56, 13, 59, 17, 44, 27, 6, 62, 11, 43, 17, 49, 38, 26, 2, 16, 27, 58, 21, 54, 18, 26, 5, 35, 61, 43, 27, 7, 39, 14, 58, 37, 55, 20, 33, 13, 40, 62, 10, 55, 5 },
+  { 51, 14, 61, 29, 59, 20, 55, 31, 0, 49, 11, 60, 3, 26, 22, 56, 0, 40, 12, 43, 41, 8, 36, 0, 17, 57, 24, 2, 46, 26, 61, 18, 0, 38, 12, 59, 6, 49, 3, 57, 19, 63, 5, 33, 18, 54, 28, 56, 0, 43, 26, 46, 63, 27, 56, 22, 27, 54, 38, 28, 63, 24, 10, 45, 0, 31, 42, 21, 12, 25, 44, 49, 59, 6, 26, 50, 3, 34, 27, 59, 0, 35, 62, 16, 4, 58, 47, 0, 43, 24, 37, 2, 54, 20, 46, 31, 0, 56, 34, 5, 55, 45, 60, 37, 0, 40, 10, 38, 63, 46, 15, 20, 0, 53, 21, 62, 30, 11, 24, 27, 40, 0, 57, 26, 3, 45, 27, 35 },
+};
+
+#else
+#define DM_WIDTH 8
+#define DM_WIDTH_SHIFT 3
+#define DM_HEIGHT 8
+static const guchar DM[8][8] =
+{
+  { 0,  32, 8,  40, 2,  34, 10, 42 },
+  { 48, 16, 56, 24, 50, 18, 58, 26 },
+  { 12, 44, 4,  36, 14, 46, 6,  38 },
+  { 60, 28, 52, 20, 62, 30, 54, 22 },
+  { 3,  35, 11, 43, 1,  33, 9,  41 },
+  { 51, 19, 59, 27, 49, 17, 57, 25 },
+  { 15, 47, 7,  39, 13, 45, 5,  37 },
+  { 63, 31, 55, 23, 61, 29, 53, 21 }
+};
+#endif
+
+static guint32 *DM_565 = NULL;
+
+static void
+gdk_rgb_preprocess_dm_565 (void)
+{
+  int i;
+  guint32 dith;
+
+  if (DM_565 == NULL)
+    {
+      DM_565 = g_new (guint32, DM_WIDTH * DM_HEIGHT);
+      for (i = 0; i < DM_WIDTH * DM_HEIGHT; i++)
+       {
+         dith = DM[0][i] >> 3;
+         DM_565[i] = (dith << 20) | dith | (((7 - dith) >> 1) << 10);
+#ifdef VERBOSE
+         g_print ("%i %x %x\n", i, dith, DM_565[i]);
+#endif
+       }
+    }
+}
+
+static void
+gdk_rgb_convert_8_d666 (GdkImage *image,
+                       gint x0, gint y0, gint width, gint height,
+                       guchar *buf, int rowstride,
+                       gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  gint bpl;
+  guchar *obuf, *obptr;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+  const guchar *dmp;
+  gint dith;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0;
+  for (y = 0; y < height; y++)
+    {
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 7;
+         r = ((r * 5) + dith) >> 8;
+         g = ((g * 5) + (262 - dith)) >> 8;
+         b = ((b * 5) + dith) >> 8;
+         obptr[0] = colorcube_d[(r << 6) | (g << 3) | b];
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_8_d (GdkImage *image,
+                    gint x0, gint y0, gint width, gint height,
+                    guchar *buf, int rowstride,
+                    gint x_align, gint y_align,
+                    GdkRgbCmap *cmap)
+{
+  int x, y;
+  gint bpl;
+  guchar *obuf, *obptr;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+  const guchar *dmp;
+  gint dith;
+  gint rs, gs, bs;
+
+  bptr = buf;
+  bpl = image->bpl;
+  rs = image_info->nred_shades - 1;
+  gs = image_info->ngreen_shades - 1;
+  bs = image_info->nblue_shades - 1;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0;
+  for (y = 0; y < height; y++)
+    {
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 7;
+         r = ((r * rs) + dith) >> 8;
+         g = ((g * gs) + (262 - dith)) >> 8;
+         b = ((b * bs) + dith) >> 8;
+         obptr[0] = colorcube_d[(r << 6) | (g << 3) | b];
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_8_indexed (GdkImage *image,
+                          gint x0, gint y0, gint width, gint height,
+                          guchar *buf, int rowstride,
+                          gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  gint bpl;
+  guchar *obuf, *obptr;
+  guchar *bptr, *bp2;
+  guchar c;
+  guchar *lut;
+
+  lut = cmap->lut;
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         c = *bp2++;
+         obptr[0] = lut[c];
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_gray8 (GdkImage *image,
+                      gint x0, gint y0, gint width, gint height,
+                      guchar *buf, int rowstride,
+                      gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  gint bpl;
+  guchar *obuf, *obptr;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         obptr[0] = (g + ((b + r) >> 1)) >> 1;
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_gray8_gray (GdkImage *image,
+                           gint x0, gint y0, gint width, gint height,
+                           guchar *buf, int rowstride,
+                           gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int y;
+  gint bpl;
+  guchar *obuf;
+  guchar *bptr;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0;
+  for (y = 0; y < height; y++)
+    {
+      memcpy (obuf, bptr, width);
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define HAIRY_CONVERT_565
+#endif
+
+#ifdef HAIRY_CONVERT_565
+/* Render a 24-bit RGB image in buf into the GdkImage, without dithering.
+   This assumes native byte ordering - what should really be done is to
+   check whether static_image->byte_order is consistent with the _ENDIAN
+   config flag, and if not, use a different function.
+
+   This one is even faster than the one below - its inner loop loads 3
+   words (i.e. 4 24-bit pixels), does a lot of shifting and masking,
+   then writes 2 words. */
+static void
+gdk_rgb_convert_565 (GdkImage *image,
+                    gint x0, gint y0, gint width, gint height,
+                    guchar *buf, int rowstride,
+                    gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf, *obptr;
+  gint bpl;
+  guchar *bptr, *bp2;
+  guchar r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+       {
+         for (x = 0; x < width; x++)
+           {
+             r = *bp2++;
+             g = *bp2++;
+             b = *bp2++;
+             ((guint16 *)obptr)[0] = ((r & 0xf8) << 8) |
+               ((g & 0xfc) << 3) |
+               (b >> 3);
+             obptr += 2;
+           }
+       }
+      else
+       {
+         for (x = 0; x < width - 3; x += 4)
+           {
+             guint32 r1b0g0r0;
+             guint32 g2r2b1g1;
+             guint32 b3g3r3b2;
+
+             r1b0g0r0 = ((guint32 *)bp2)[0];
+             g2r2b1g1 = ((guint32 *)bp2)[1];
+             b3g3r3b2 = ((guint32 *)bp2)[2];
+             ((guint32 *)obptr)[0] =
+               ((r1b0g0r0 & 0xf8) << 8) |
+               ((r1b0g0r0 & 0xfc00) >> 5) |
+               ((r1b0g0r0 & 0xf80000) >> 19) |
+               (r1b0g0r0 & 0xf8000000) |
+               ((g2r2b1g1 & 0xfc) << 19) |
+               ((g2r2b1g1 & 0xf800) << 5);
+             ((guint32 *)obptr)[1] =
+               ((g2r2b1g1 & 0xf80000) >> 8) |
+               ((g2r2b1g1 & 0xfc000000) >> 21) |
+               ((b3g3r3b2 & 0xf8) >> 3) |
+               ((b3g3r3b2 & 0xf800) << 16) |
+               ((b3g3r3b2 & 0xfc0000) << 3) |
+               ((b3g3r3b2 & 0xf8000000) >> 11);
+             bp2 += 12;
+             obptr += 8;
+           }
+         for (; x < width; x++)
+           {
+             r = *bp2++;
+             g = *bp2++;
+             b = *bp2++;
+             ((guint16 *)obptr)[0] = ((r & 0xf8) << 8) |
+               ((g & 0xfc) << 3) |
+               (b >> 3);
+             obptr += 2;
+           }
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#else
+/* Render a 24-bit RGB image in buf into the GdkImage, without dithering.
+   This assumes native byte ordering - what should really be done is to
+   check whether static_image->byte_order is consistent with the _ENDIAN
+   config flag, and if not, use a different function.
+
+   This routine is faster than the one included with Gtk 1.0 for a number
+   of reasons:
+
+   1. Shifting instead of lookup tables (less memory traffic).
+
+   2. Much less register pressure, especially because shifts are
+   in the code.
+
+   3. A memcpy is avoided (i.e. the transfer function).
+
+   4. On big-endian architectures, byte swapping is avoided.
+
+   That said, it wouldn't be hard to make it even faster - just make an
+   inner loop that reads 3 words (i.e. 4 24-bit pixels), does a lot of
+   shifting and masking, then writes 2 words.
+*/
+static void
+gdk_rgb_convert_565 (GdkImage *image,
+                    gint x0, gint y0, gint width, gint height,
+                    guchar *buf, int rowstride,
+                    gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf;
+  gint bpl;
+  guchar *bptr, *bp2;
+  guchar r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         ((unsigned short *)obuf)[x] = ((r & 0xf8) << 8) |
+           ((g & 0xfc) << 3) |
+           (b >> 3);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#endif
+
+#ifdef HAIRY_CONVERT_565
+static void
+gdk_rgb_convert_565_gray (GdkImage *image,
+                         gint x0, gint y0, gint width, gint height,
+                         guchar *buf, int rowstride,
+                         gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf, *obptr;
+  gint bpl;
+  guchar *bptr, *bp2;
+  guchar g;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+       {
+         for (x = 0; x < width; x++)
+           {
+             g = *bp2++;
+             ((guint16 *)obptr)[0] = ((g & 0xf8) << 8) |
+               ((g & 0xfc) << 3) |
+               (g >> 3);
+             obptr += 2;
+           }
+       }
+      else
+       {
+         for (x = 0; x < width - 3; x += 4)
+           {
+             guint32 g3g2g1g0;
+
+             g3g2g1g0 = ((guint32 *)bp2)[0];
+             ((guint32 *)obptr)[0] =
+               ((g3g2g1g0 & 0xf8) << 8) |
+               ((g3g2g1g0 & 0xfc) << 3) |
+               ((g3g2g1g0 & 0xf8) >> 3) |
+               (g3g2g1g0 & 0xf800) << 16 |
+               ((g3g2g1g0 & 0xfc00) << 11) |
+               ((g3g2g1g0 & 0xf800) << 5);
+             ((guint32 *)obptr)[1] =
+               ((g3g2g1g0 & 0xf80000) >> 8) |
+               ((g3g2g1g0 & 0xfc0000) >> 13) |
+               ((g3g2g1g0 & 0xf80000) >> 19) |
+               (g3g2g1g0 & 0xf8000000) |
+               ((g3g2g1g0 & 0xfc000000) >> 5) |
+               ((g3g2g1g0 & 0xf8000000) >> 11);
+             bp2 += 4;
+             obptr += 8;
+           }
+         for (; x < width; x++)
+           {
+             g = *bp2++;
+             ((guint16 *)obptr)[0] = ((g & 0xf8) << 8) |
+               ((g & 0xfc) << 3) |
+               (g >> 3);
+             obptr += 2;
+           }
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#else
+static void
+gdk_rgb_convert_565_gray (GdkImage *image,
+                         gint x0, gint y0, gint width, gint height,
+                         guchar *buf, int rowstride,
+                         gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf;
+  gint bpl;
+  guchar *bptr, *bp2;
+  guchar g;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         g = *bp2++;
+         ((guint16 *)obuf)[x] = ((g & 0xf8) << 8) |
+           ((g & 0xfc) << 3) |
+           (g >> 3);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#endif
+
+static void
+gdk_rgb_convert_565_br (GdkImage *image,
+                       gint x0, gint y0, gint width, gint height,
+                       guchar *buf, int rowstride,
+                       gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf;
+  gint bpl;
+  guchar *bptr, *bp2;
+  guchar r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         /* final word is:
+            g4 g3 g2 b7 b6 b5 b4 b3  r7 r6 r5 r4 r3 g7 g6 g5
+          */
+         ((unsigned short *)obuf)[x] = (r & 0xf8) |
+           ((g & 0xe0) >> 5) |
+           ((g & 0x1c) << 11) |
+           ((b & 0xf8) << 5);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* Thanks to Ray Lehtiniemi for a patch that resulted in a ~25% speedup
+   in this mode. */
+#ifdef HAIRY_CONVERT_565
+static void
+gdk_rgb_convert_565_d (GdkImage *image,
+                    gint x0, gint y0, gint width, gint height,
+                    guchar *buf, int rowstride,
+                    gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  /* Now this is what I'd call some highly tuned code! */
+  int x, y;
+  guchar *obuf, *obptr;
+  gint bpl;
+  guchar *bptr, *bp2;
+
+  width += x_align;
+  height += y_align;
+  
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2;
+  for (y = y_align; y < height; y++)
+    {
+      guint32 *dmp = DM_565 + ((y & (DM_HEIGHT - 1)) << DM_WIDTH_SHIFT);
+      bp2 = bptr;
+      obptr = obuf;
+      if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+       {
+         for (x = x_align; x < width; x++)
+           {
+             gint32 rgb = *bp2++ << 20;
+             rgb += *bp2++ << 10;
+             rgb += *bp2++;
+             rgb += dmp[x & (DM_WIDTH - 1)];
+             rgb += 0x10040100
+               - ((rgb & 0x1e0001e0) >> 5)
+               - ((rgb & 0x00070000) >> 6);
+
+             ((unsigned short *)obptr)[0] =
+               ((rgb & 0x0f800000) >> 12) |
+               ((rgb & 0x0003f000) >> 7) |
+               ((rgb & 0x000000f8) >> 3);
+             obptr += 2;
+           }
+       }
+      else
+       {
+         for (x = x_align; x < width - 3; x += 4)
+           {
+             guint32 r1b0g0r0;
+             guint32 g2r2b1g1;
+             guint32 b3g3r3b2;
+             guint32 rgb02, rgb13;
+
+             r1b0g0r0 = ((guint32 *)bp2)[0];
+             g2r2b1g1 = ((guint32 *)bp2)[1];
+             b3g3r3b2 = ((guint32 *)bp2)[2];
+             rgb02 =
+               ((r1b0g0r0 & 0xff) << 20) +
+               ((r1b0g0r0 & 0xff00) << 2) +
+               ((r1b0g0r0 & 0xff0000) >> 16) +
+               dmp[x & (DM_WIDTH - 1)];
+             rgb02 += 0x10040100
+               - ((rgb02 & 0x1e0001e0) >> 5)
+               - ((rgb02 & 0x00070000) >> 6);
+             rgb13 =
+               ((r1b0g0r0 & 0xff000000) >> 4) +
+               ((g2r2b1g1 & 0xff) << 10) +
+               ((g2r2b1g1 & 0xff00) >> 8) +
+               dmp[(x + 1) & (DM_WIDTH - 1)];
+             rgb13 += 0x10040100
+               - ((rgb13 & 0x1e0001e0) >> 5)
+               - ((rgb13 & 0x00070000) >> 6);
+             ((guint32 *)obptr)[0] =
+               ((rgb02 & 0x0f800000) >> 12) |
+               ((rgb02 & 0x0003f000) >> 7) |
+               ((rgb02 & 0x000000f8) >> 3) |
+               ((rgb13 & 0x0f800000) << 4) |
+               ((rgb13 & 0x0003f000) << 9) |
+               ((rgb13 & 0x000000f8) << 13);
+             rgb02 =
+               ((g2r2b1g1 & 0xff0000) << 4) +
+               ((g2r2b1g1 & 0xff000000) >> 14) +
+               (b3g3r3b2 & 0xff) +
+               dmp[(x + 2) & (DM_WIDTH - 1)];
+             rgb02 += 0x10040100
+               - ((rgb02 & 0x1e0001e0) >> 5)
+               - ((rgb02 & 0x00070000) >> 6);
+             rgb13 =
+               ((b3g3r3b2 & 0xff00) << 12) +
+               ((b3g3r3b2 & 0xff0000) >> 6) +
+               ((b3g3r3b2 & 0xff000000) >> 24) +
+               dmp[(x + 3) & (DM_WIDTH - 1)];
+             rgb13 += 0x10040100
+               - ((rgb13 & 0x1e0001e0) >> 5)
+               - ((rgb13 & 0x00070000) >> 6);
+             ((guint32 *)obptr)[1] =
+               ((rgb02 & 0x0f800000) >> 12) |
+               ((rgb02 & 0x0003f000) >> 7) |
+               ((rgb02 & 0x000000f8) >> 3) |
+               ((rgb13 & 0x0f800000) << 4) |
+               ((rgb13 & 0x0003f000) << 9) |
+               ((rgb13 & 0x000000f8) << 13);
+             bp2 += 12;
+             obptr += 8;
+           }
+         for (; x < width; x++)
+           {
+             gint32 rgb = *bp2++ << 20;
+             rgb += *bp2++ << 10;
+             rgb += *bp2++;
+             rgb += dmp[x & (DM_WIDTH - 1)];
+             rgb += 0x10040100
+               - ((rgb & 0x1e0001e0) >> 5)
+               - ((rgb & 0x00070000) >> 6);
+
+             ((unsigned short *)obptr)[0] =
+               ((rgb & 0x0f800000) >> 12) |
+               ((rgb & 0x0003f000) >> 7) |
+               ((rgb & 0x000000f8) >> 3);
+             obptr += 2;
+           }
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#else
+static void
+gdk_rgb_convert_565_d (GdkImage *image,
+                       gint x0, gint y0, gint width, gint height,
+                       guchar *buf, int rowstride,
+                       gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf;
+  gint bpl;
+  guchar *bptr;
+
+  width += x_align;
+  height += y_align;
+  
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + (x0 - x_align) * 2;
+
+  for (y = y_align; y < height; y++)
+    {
+      guint32 *dmp = DM_565 + ((y & (DM_HEIGHT - 1)) << DM_WIDTH_SHIFT);
+      guchar *bp2 = bptr;
+
+      for (x = x_align; x < width; x++)
+        {
+          gint32 rgb = *bp2++ << 20;
+          rgb += *bp2++ << 10;
+          rgb += *bp2++;
+         rgb += dmp[x & (DM_WIDTH - 1)];
+          rgb += 0x10040100
+            - ((rgb & 0x1e0001e0) >> 5)
+            - ((rgb & 0x00070000) >> 6);
+
+          ((unsigned short *)obuf)[x] =
+            ((rgb & 0x0f800000) >> 12) |
+            ((rgb & 0x0003f000) >> 7) |
+            ((rgb & 0x000000f8) >> 3);
+        }
+
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#endif
+
+static void
+gdk_rgb_convert_555 (GdkImage *image,
+                    gint x0, gint y0, gint width, gint height,
+                    guchar *buf, int rowstride,
+                    gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf;
+  gint bpl;
+  guchar *bptr, *bp2;
+  guchar r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         ((unsigned short *)obuf)[x] = ((r & 0xf8) << 7) |
+           ((g & 0xf8) << 2) |
+           (b >> 3);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_555_br (GdkImage *image,
+                       gint x0, gint y0, gint width, gint height,
+                       guchar *buf, int rowstride,
+                       gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf;
+  gint bpl;
+  guchar *bptr, *bp2;
+  guchar r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         /* final word is:
+            g5 g4 g3 b7 b6 b5 b4 b3  0 r7 r6 r5 r4 r3 g7 g6
+          */
+         ((unsigned short *)obuf)[x] = ((r & 0xf8) >> 1) |
+           ((g & 0xc0) >> 6) |
+           ((g & 0x18) << 10) |
+           ((b & 0xf8) << 5);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_888_msb (GdkImage *image,
+                        gint x0, gint y0, gint width, gint height,
+                        guchar *buf, int rowstride,
+                        gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int y;
+  guchar *obuf;
+  gint bpl;
+  guchar *bptr;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 3;
+  for (y = 0; y < height; y++)
+    {
+      memcpy (obuf, bptr, width + width + width);
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* todo: optimize this */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define HAIRY_CONVERT_888
+#endif
+
+#ifdef HAIRY_CONVERT_888
+static void
+gdk_rgb_convert_888_lsb (GdkImage *image,
+                        gint x0, gint y0, gint width, gint height,
+                        guchar *buf, int rowstride,
+                        gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf, *obptr;
+  gint bpl;
+  guchar *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 3;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+       {
+         for (x = 0; x < width; x++)
+           {
+             r = bp2[0];
+             g = bp2[1];
+             b = bp2[2];
+             *obptr++ = b;
+             *obptr++ = g;
+             *obptr++ = r;
+             bp2 += 3;
+           }
+       }
+      else
+       {
+         for (x = 0; x < width - 3; x += 4)
+           {
+             guint32 r1b0g0r0;
+             guint32 g2r2b1g1;
+             guint32 b3g3r3b2;
+
+             r1b0g0r0 = ((guint32 *)bp2)[0];
+             g2r2b1g1 = ((guint32 *)bp2)[1];
+             b3g3r3b2 = ((guint32 *)bp2)[2];
+             ((guint32 *)obptr)[0] =
+               (r1b0g0r0 & 0xff00) |
+               ((r1b0g0r0 & 0xff0000) >> 16) |
+               (((g2r2b1g1 & 0xff00) | (r1b0g0r0 & 0xff)) << 16);
+             ((guint32 *)obptr)[1] =
+               (g2r2b1g1 & 0xff0000ff) |
+               ((r1b0g0r0 & 0xff000000) >> 16) |
+               ((b3g3r3b2 & 0xff) << 16);
+             ((guint32 *)obptr)[2] =
+               (((g2r2b1g1 & 0xff0000) | (b3g3r3b2 & 0xff000000)) >> 16) |
+               ((b3g3r3b2 & 0xff00) << 16) |
+               ((b3g3r3b2 & 0xff0000));
+             bp2 += 12;
+             obptr += 12;
+           }
+         for (; x < width; x++)
+           {
+             r = bp2[0];
+             g = bp2[1];
+             b = bp2[2];
+             *obptr++ = b;
+             *obptr++ = g;
+             *obptr++ = r;
+             bp2 += 3;
+           }
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#else
+static void
+gdk_rgb_convert_888_lsb (GdkImage *image,
+                        gint x0, gint y0, gint width, gint height,
+                        guchar *buf, int rowstride,
+                        gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf;
+  gint bpl;
+  guchar *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 3;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         obuf[x * 3] = b;
+         obuf[x * 3 + 1] = g;
+         obuf[x * 3 + 2] = r;
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+#endif
+
+/* convert 24-bit packed to 32-bit unpacked */
+/* todo: optimize this */
+static void
+gdk_rgb_convert_0888 (GdkImage *image,
+                     gint x0, gint y0, gint width, gint height,
+                     guchar *buf, int rowstride,
+                     gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf;
+  gint bpl;
+  guchar *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 4;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         ((guint32 *)obuf)[x] = (r << 16) | (g << 8) | b;
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_0888_br (GdkImage *image,
+                        gint x0, gint y0, gint width, gint height,
+                        guchar *buf, int rowstride,
+                        gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf;
+  gint bpl;
+  guchar *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 4;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         ((guint32 *)obuf)[x] = (b << 24) | (g << 16) | (r << 8);
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_8880_br (GdkImage *image,
+                        gint x0, gint y0, gint width, gint height,
+                        guchar *buf, int rowstride,
+                        gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf;
+  gint bpl;
+  guchar *bptr, *bp2;
+  int r, g, b;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 4;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         ((guint32 *)obuf)[x] = (b << 16) | (g << 8) | r;
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* Generic truecolor/directcolor conversion function. Slow, but these
+   are oddball modes. */
+static void
+gdk_rgb_convert_truecolor_lsb (GdkImage *image,
+                              gint x0, gint y0, gint width, gint height,
+                              guchar *buf, int rowstride,
+                              gint x_align, gint y_align,
+                              GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf, *obptr;
+  gint bpl;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+  gint r_right, r_left;
+  gint g_right, g_left;
+  gint b_right, b_left;
+  gint bpp;
+  guint32 pixel;
+  gint i;
+
+  r_right = 8 - image_info->visual->red_prec;
+  r_left = image_info->visual->red_shift;
+  g_right = 8 - image_info->visual->green_prec;
+  g_left = image_info->visual->green_shift;
+  b_right = 8 - image_info->visual->blue_prec;
+  b_left = image_info->visual->blue_shift;
+  bpp = image_info->bpp;
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * bpp;
+  for (y = 0; y < height; y++)
+    {
+      obptr = obuf;
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         pixel = ((r >> r_right) << r_left) |
+           ((g >> g_right) << g_left) |
+           ((b >> b_right) << b_left);
+         for (i = 0; i < bpp; i++)
+           {
+             *obptr++ = pixel & 0xff;
+             pixel >>= 8;
+           }
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_truecolor_lsb_d (GdkImage *image,
+                                gint x0, gint y0, gint width, gint height,
+                                guchar *buf, int rowstride,
+                                gint x_align, gint y_align,
+                                GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf, *obptr;
+  gint bpl;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+  gint r_right, r_left, r_prec;
+  gint g_right, g_left, g_prec;
+  gint b_right, b_left, b_prec;
+  gint bpp;
+  guint32 pixel;
+  gint i;
+  gint dith;
+  gint r1, g1, b1;
+  const guchar *dmp;
+
+  r_right = 8 - image_info->visual->red_prec;
+  r_left = image_info->visual->red_shift;
+  r_prec = image_info->visual->red_prec;
+  g_right = 8 - image_info->visual->green_prec;
+  g_left = image_info->visual->green_shift;
+  g_prec = image_info->visual->green_prec;
+  b_right = 8 - image_info->visual->blue_prec;
+  b_left = image_info->visual->blue_shift;
+  b_prec = image_info->visual->blue_prec;
+  bpp = image_info->bpp;
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * bpp;
+  for (y = 0; y < height; y++)
+    {
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      obptr = obuf;
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         dith = dmp[(x_align + x) & (DM_WIDTH - 1)] << 2;
+         r1 = r + (dith >> r_prec);
+         g1 = g + ((252 - dith) >> g_prec);
+         b1 = b + (dith >> b_prec);
+         pixel = (((r1 - (r1 >> r_prec)) >> r_right) << r_left) |
+           (((g1 - (g1 >> g_prec)) >> g_right) << g_left) |
+           (((b1 - (b1 >> b_prec)) >> b_right) << b_left);
+         for (i = 0; i < bpp; i++)
+           {
+             *obptr++ = pixel & 0xff;
+             pixel >>= 8;
+           }
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_truecolor_msb (GdkImage *image,
+                              gint x0, gint y0, gint width, gint height,
+                              guchar *buf, int rowstride,
+                              gint x_align, gint y_align,
+                              GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf, *obptr;
+  gint bpl;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+  gint r_right, r_left;
+  gint g_right, g_left;
+  gint b_right, b_left;
+  gint bpp;
+  guint32 pixel;
+  gint shift, shift_init;
+
+  r_right = 8 - image_info->visual->red_prec;
+  r_left = image_info->visual->red_shift;
+  g_right = 8 - image_info->visual->green_prec;
+  g_left = image_info->visual->green_shift;
+  b_right = 8 - image_info->visual->blue_prec;
+  b_left = image_info->visual->blue_shift;
+  bpp = image_info->bpp;
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * bpp;
+  shift_init = (bpp - 1) << 3;
+  for (y = 0; y < height; y++)
+    {
+      obptr = obuf;
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         pixel = ((r >> r_right) << r_left) |
+           ((g >> g_right) << g_left) |
+           ((b >> b_right) << b_left);
+         for (shift = shift_init; shift >= 0; shift -= 8)
+           {
+             *obptr++ = (pixel >> shift) & 0xff;
+           }
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_truecolor_msb_d (GdkImage *image,
+                                gint x0, gint y0, gint width, gint height,
+                                guchar *buf, int rowstride,
+                                gint x_align, gint y_align,
+                                GdkRgbCmap *cmap)
+{
+  int x, y;
+  guchar *obuf, *obptr;
+  gint bpl;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+  gint r_right, r_left, r_prec;
+  gint g_right, g_left, g_prec;
+  gint b_right, b_left, b_prec;
+  gint bpp;
+  guint32 pixel;
+  gint shift, shift_init;
+  gint dith;
+  gint r1, g1, b1;
+  const guchar *dmp;
+
+  r_right = 8 - image_info->visual->red_prec;
+  r_left = image_info->visual->red_shift;
+  r_prec = image_info->visual->red_prec;
+  g_right = 8 - image_info->visual->green_prec;
+  g_left = image_info->visual->green_shift;
+  g_prec = image_info->visual->green_prec;
+  b_right = 8 - image_info->visual->blue_prec;
+  b_left = image_info->visual->blue_shift;
+  b_prec = image_info->visual->blue_prec;
+  bpp = image_info->bpp;
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0 * bpp;
+  shift_init = (bpp - 1) << 3;
+  for (y = 0; y < height; y++)
+    {
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      obptr = obuf;
+      bp2 = bptr;
+      for (x = 0; x < width; x++)
+       {
+         r = bp2[0];
+         g = bp2[1];
+         b = bp2[2];
+         dith = dmp[(x_align + x) & (DM_WIDTH - 1)] << 2;
+         r1 = r + (dith >> r_prec);
+         g1 = g + ((252 - dith) >> g_prec);
+         b1 = b + (dith >> b_prec);
+         pixel = (((r1 - (r1 >> r_prec)) >> r_right) << r_left) |
+           (((g1 - (g1 >> g_prec)) >> g_right) << g_left) |
+           (((b1 - (b1 >> b_prec)) >> b_right) << b_left);
+         for (shift = shift_init; shift >= 0; shift -= 8)
+           {
+             *obptr++ = (pixel >> shift) & 0xff;
+           }
+         bp2 += 3;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* This actually works for depths from 3 to 7 */
+static void
+gdk_rgb_convert_4 (GdkImage *image,
+                  gint x0, gint y0, gint width, gint height,
+                  guchar *buf, int rowstride,
+                  gint x_align, gint y_align,
+                  GdkRgbCmap *cmap)
+{
+  int x, y;
+  gint bpl;
+  guchar *obuf, *obptr;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+  const guchar *dmp;
+  gint dith;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0;
+  for (y = 0; y < height; y++)
+    {
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x += 1)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 3;
+         obptr[0] = colorcube_d[(((r + dith) & 0x100) >> 2) |
+                               (((g + 258 - dith) & 0x100) >> 5) |
+                               (((b + dith) & 0x100) >> 8)];
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* This actually works for depths from 3 to 7 */
+static void
+gdk_rgb_convert_gray4 (GdkImage *image,
+                      gint x0, gint y0, gint width, gint height,
+                      guchar *buf, int rowstride,
+                      gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  gint bpl;
+  guchar *obuf, *obptr;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+  gint shift;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0;
+  shift = 9 - image_info->visual->depth;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         obptr[0] = (g + ((b + r) >> 1)) >> shift;
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_gray4_pack (GdkImage *image,
+                           gint x0, gint y0, gint width, gint height,
+                           guchar *buf, int rowstride,
+                           gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  gint bpl;
+  guchar *obuf, *obptr;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+  gint shift;
+  guchar pix0, pix1;
+  /* todo: this is hardcoded to big-endian. Make endian-agile. */
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + (x0 >> 1);
+  shift = 9 - image_info->visual->depth;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x += 2)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         pix0 = (g + ((b + r) >> 1)) >> shift;
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         pix1 = (g + ((b + r) >> 1)) >> shift;
+         obptr[0] = (pix0 << 4) | pix1;
+         obptr++;
+       }
+      if (width & 1)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         pix0 = (g + ((b + r) >> 1)) >> shift;
+         obptr[0] = (pix0 << 4);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* This actually works for depths from 3 to 7 */
+static void
+gdk_rgb_convert_gray4_d (GdkImage *image,
+                      gint x0, gint y0, gint width, gint height,
+                      guchar *buf, int rowstride,
+                      gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  gint bpl;
+  guchar *obuf, *obptr;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+  const guchar *dmp;
+  gint prec, right;
+  gint gray;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + x0;
+  prec = image_info->visual->depth;
+  right = 8 - prec;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         gray = (g + ((b + r) >> 1)) >> 1;
+         gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec;
+         obptr[0] = (gray - (gray >> prec)) >> right;
+         obptr++;
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_gray4_d_pack (GdkImage *image,
+                             gint x0, gint y0, gint width, gint height,
+                             guchar *buf, int rowstride,
+                             gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  int x, y;
+  gint bpl;
+  guchar *obuf, *obptr;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+  const guchar *dmp;
+  gint prec, right;
+  gint gray;
+  guchar pix0, pix1;
+  /* todo: this is hardcoded to big-endian. Make endian-agile. */
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + (x0 >> 1);
+  prec = image_info->visual->depth;
+  right = 8 - prec;
+  for (y = 0; y < height; y++)
+    {
+      bp2 = bptr;
+      obptr = obuf;
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      for (x = 0; x < width; x += 2)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         gray = (g + ((b + r) >> 1)) >> 1;
+         gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec;
+         pix0 = (gray - (gray >> prec)) >> right;
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         gray = (g + ((b + r) >> 1)) >> 1;
+         gray += (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) >> prec;
+         pix1 = (gray - (gray >> prec)) >> right;
+         obptr[0] = (pix0 << 4) | pix1;
+         obptr++;
+       }
+      if (width & 1)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         gray = (g + ((b + r) >> 1)) >> 1;
+         gray += (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) >> prec;
+         pix0 = (gray - (gray >> prec)) >> right;
+         obptr[0] = (pix0 << 4);
+       }
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+static void
+gdk_rgb_convert_1 (GdkImage *image,
+                  gint x0, gint y0, gint width, gint height,
+                  guchar *buf, int rowstride,
+                  gint x_align, gint y_align,
+                  GdkRgbCmap *cmap)
+{
+  int x, y;
+  gint bpl;
+  guchar *obuf, *obptr;
+  guchar *bptr, *bp2;
+  gint r, g, b;
+  const guchar *dmp;
+  gint dith;
+  guchar byte;
+
+  bptr = buf;
+  bpl = image->bpl;
+  obuf = ((guchar *)image->mem) + y0 * bpl + (x0 >> 3);
+  byte = 0; /* unnecessary, but it keeps gcc from complaining */
+  for (y = 0; y < height; y++)
+    {
+      dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+      bp2 = bptr;
+      obptr = obuf;
+      for (x = 0; x < width; x++)
+       {
+         r = *bp2++;
+         g = *bp2++;
+         b = *bp2++;
+         dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 4) | 4;
+         byte += byte + (r + g + g + b + dith > 1020);
+         if ((x & 7) == 7)
+           {
+             obptr[0] = byte;
+             obptr++;
+           }
+       }
+      if (x & 7)
+       obptr[0] = byte << (8 - (x & 7));
+      bptr += rowstride;
+      obuf += bpl;
+    }
+}
+
+/* Returns a pointer to the stage buffer. */
+static guchar *
+gdk_rgb_ensure_stage (void)
+{
+  if (image_info->stage_buf == NULL)
+    image_info->stage_buf = g_malloc (IMAGE_HEIGHT * STAGE_ROWSTRIDE);
+  return image_info->stage_buf;
+}
+
+/* This is slow. Speed me up, please. */
+static void
+gdk_rgb_32_to_stage (guchar *buf, gint rowstride, gint width, gint height)
+{
+  gint x, y;
+  guchar *pi_start, *po_start;
+  guchar *pi, *po;
+
+  pi_start = buf;
+  po_start = gdk_rgb_ensure_stage ();
+  for (y = 0; y < height; y++)
+    {
+      pi = pi_start;
+      po = po_start;
+      for (x = 0; x < width; x++)
+       {
+         *po++ = *pi++;
+         *po++ = *pi++;
+         *po++ = *pi++;
+         pi++;
+       }
+      pi_start += rowstride;
+      po_start += STAGE_ROWSTRIDE;
+    }
+}
+
+/* Generic 32bit RGB conversion function - convert to 24bit packed, then
+   go from there. */
+static void
+gdk_rgb_convert_32_generic (GdkImage *image,
+                           gint x0, gint y0, gint width, gint height,
+                           guchar *buf, gint rowstride,
+                           gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  gdk_rgb_32_to_stage (buf, rowstride, width, height);
+
+  (*image_info->conv) (image, x0, y0, width, height,
+                      image_info->stage_buf, STAGE_ROWSTRIDE,
+                      x_align, y_align, cmap);
+}
+
+/* Generic 32bit RGB conversion function - convert to 24bit packed, then
+   go from there. */
+static void
+gdk_rgb_convert_32_generic_d (GdkImage *image,
+                             gint x0, gint y0, gint width, gint height,
+                             guchar *buf, gint rowstride,
+                             gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  gdk_rgb_32_to_stage (buf, rowstride, width, height);
+
+  (*image_info->conv_d) (image, x0, y0, width, height,
+                        image_info->stage_buf, STAGE_ROWSTRIDE,
+                        x_align, y_align, cmap);
+}
+
+/* This is slow. Speed me up, please. */
+static void
+gdk_rgb_gray_to_stage (guchar *buf, gint rowstride, gint width, gint height)
+{
+  gint x, y;
+  guchar *pi_start, *po_start;
+  guchar *pi, *po;
+  guchar gray;
+
+  pi_start = buf;
+  po_start = gdk_rgb_ensure_stage ();
+  for (y = 0; y < height; y++)
+    {
+      pi = pi_start;
+      po = po_start;
+      for (x = 0; x < width; x++)
+       {
+         gray = *pi++;
+         *po++ = gray;
+         *po++ = gray;
+         *po++ = gray;
+       }
+      pi_start += rowstride;
+      po_start += STAGE_ROWSTRIDE;
+    }
+}
+
+/* Generic gray conversion function - convert to 24bit packed, then go
+   from there. */
+static void
+gdk_rgb_convert_gray_generic (GdkImage *image,
+                             gint x0, gint y0, gint width, gint height,
+                             guchar *buf, gint rowstride,
+                             gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  gdk_rgb_gray_to_stage (buf, rowstride, width, height);
+
+  (*image_info->conv) (image, x0, y0, width, height,
+                      image_info->stage_buf, STAGE_ROWSTRIDE,
+                      x_align, y_align, cmap);
+}
+
+static void
+gdk_rgb_convert_gray_generic_d (GdkImage *image,
+                               gint x0, gint y0, gint width, gint height,
+                               guchar *buf, gint rowstride,
+                               gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  gdk_rgb_gray_to_stage (buf, rowstride, width, height);
+
+  (*image_info->conv_d) (image, x0, y0, width, height,
+                        image_info->stage_buf, STAGE_ROWSTRIDE,
+                        x_align, y_align, cmap);
+}
+
+/* Render grayscale using indexed method. */
+static void
+gdk_rgb_convert_gray_cmap (GdkImage *image,
+                          gint x0, gint y0, gint width, gint height,
+                          guchar *buf, gint rowstride,
+                          gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  (*image_info->conv_indexed) (image, x0, y0, width, height,
+                              buf, rowstride,
+                              x_align, y_align, image_info->gray_cmap);
+}
+
+#if 0
+static void
+gdk_rgb_convert_gray_cmap_d (GdkImage *image,
+                               gint x0, gint y0, gint width, gint height,
+                               guchar *buf, gint rowstride,
+                               gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  (*image_info->conv_indexed_d) (image, x0, y0, width, height,
+                                buf, rowstride,
+                                x_align, y_align, image_info->gray_cmap);
+}
+#endif
+
+/* This is slow. Speed me up, please. */
+static void
+gdk_rgb_indexed_to_stage (guchar *buf, gint rowstride, gint width, gint height,
+                         GdkRgbCmap *cmap)
+{
+  gint x, y;
+  guchar *pi_start, *po_start;
+  guchar *pi, *po;
+  gint rgb;
+
+  pi_start = buf;
+  po_start = gdk_rgb_ensure_stage ();
+  for (y = 0; y < height; y++)
+    {
+      pi = pi_start;
+      po = po_start;
+      for (x = 0; x < width; x++)
+       {
+         rgb = cmap->colors[*pi++];
+         *po++ = rgb >> 16;
+         *po++ = (rgb >> 8) & 0xff;
+         *po++ = rgb & 0xff;
+       }
+      pi_start += rowstride;
+      po_start += STAGE_ROWSTRIDE;
+    }
+}
+
+/* Generic gray conversion function - convert to 24bit packed, then go
+   from there. */
+static void
+gdk_rgb_convert_indexed_generic (GdkImage *image,
+                                gint x0, gint y0, gint width, gint height,
+                                guchar *buf, gint rowstride,
+                                gint x_align, gint y_align, GdkRgbCmap *cmap)
+{
+  gdk_rgb_indexed_to_stage (buf, rowstride, width, height, cmap);
+
+  (*image_info->conv) (image, x0, y0, width, height,
+                      image_info->stage_buf, STAGE_ROWSTRIDE,
+                      x_align, y_align, cmap);
+}
+
+static void
+gdk_rgb_convert_indexed_generic_d (GdkImage *image,
+                                  gint x0, gint y0, gint width, gint height,
+                                  guchar *buf, gint rowstride,
+                                  gint x_align, gint y_align,
+                                  GdkRgbCmap *cmap)
+{
+  gdk_rgb_indexed_to_stage (buf, rowstride, width, height, cmap);
+
+  (*image_info->conv_d) (image, x0, y0, width, height,
+                        image_info->stage_buf, STAGE_ROWSTRIDE,
+                        x_align, y_align, cmap);
+}
+
+/* Select a conversion function based on the visual and a
+   representative image. */
+static void
+gdk_rgb_select_conv (GdkImage *image)
+{
+  GdkByteOrder byte_order;
+  gint depth, bpp, byterev;
+  GdkVisualType vtype;
+  guint32 red_mask, green_mask, blue_mask;
+  GdkRgbConvFunc conv, conv_d;
+  GdkRgbConvFunc conv_32, conv_32_d;
+  GdkRgbConvFunc conv_gray, conv_gray_d;
+  GdkRgbConvFunc conv_indexed, conv_indexed_d;
+  gboolean mask_rgb, mask_bgr;
+
+  depth = image_info->visual->depth;
+#if !defined (X_DISPLAY_MISSING)
+  bpp = ((GdkImagePrivate *)image)->ximage->bits_per_pixel;
+#elif defined (WINDOWS_DISPLAY)
+  bpp = ((GdkVisualPrivate *) gdk_visual_get_system())->xvisual->bitspixel;
+#endif
+  byte_order = image->byte_order;
+  if (gdk_rgb_verbose)
+    g_print ("Chose visual 0x%x, image bpp=%d, depth = %d %s first\n",
+            (gint)(((GdkVisualPrivate *)image_info->visual)->xvisual->visualid),
+            bpp, depth, byte_order == GDK_LSB_FIRST ? "lsb" : "msb");
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  byterev = (byte_order == GDK_LSB_FIRST);
+#else
+  byterev = (byte_order == GDK_MSB_FIRST);
+#endif
+
+  vtype = image_info->visual->type;
+  if (vtype == GDK_VISUAL_DIRECT_COLOR)
+    vtype = GDK_VISUAL_TRUE_COLOR;
+
+  red_mask = image_info->visual->red_mask;
+  green_mask = image_info->visual->green_mask;
+  blue_mask = image_info->visual->blue_mask;
+
+  mask_rgb = red_mask == 0xff0000 && green_mask == 0xff00 && blue_mask == 0xff;
+  mask_bgr = red_mask == 0xff && green_mask == 0xff00 && blue_mask == 0xff0000;
+
+  conv = NULL;
+  conv_d = NULL;
+
+  conv_32 = gdk_rgb_convert_32_generic;
+  conv_32_d = gdk_rgb_convert_32_generic_d;
+
+  conv_gray = gdk_rgb_convert_gray_generic;
+  conv_gray_d = gdk_rgb_convert_gray_generic_d;
+
+  conv_indexed = gdk_rgb_convert_indexed_generic;
+  conv_indexed_d = gdk_rgb_convert_indexed_generic_d;
+
+  image_info->dith_default = FALSE;
+
+  if (image_info->bitmap)
+    conv = gdk_rgb_convert_1;
+  else if (bpp == 16 && depth == 16 && !byterev &&
+      red_mask == 0xf800 && green_mask == 0x7e0 && blue_mask == 0x1f)
+    {
+      conv = gdk_rgb_convert_565;
+      conv_d = gdk_rgb_convert_565_d;
+      conv_gray = gdk_rgb_convert_565_gray;
+      gdk_rgb_preprocess_dm_565 ();
+    }
+  else if (bpp == 16 && depth == 16 &&
+          vtype == GDK_VISUAL_TRUE_COLOR && byterev &&
+      red_mask == 0xf800 && green_mask == 0x7e0 && blue_mask == 0x1f)
+    conv = gdk_rgb_convert_565_br;
+
+  else if (bpp == 16 && depth == 15 &&
+          vtype == GDK_VISUAL_TRUE_COLOR && !byterev &&
+      red_mask == 0x7c00 && green_mask == 0x3e0 && blue_mask == 0x1f)
+    conv = gdk_rgb_convert_555;
+
+  else if (bpp == 16 && depth == 15 &&
+          vtype == GDK_VISUAL_TRUE_COLOR && byterev &&
+      red_mask == 0x7c00 && green_mask == 0x3e0 && blue_mask == 0x1f)
+    conv = gdk_rgb_convert_555_br;
+
+  /* I'm not 100% sure about the 24bpp tests - but testing will show*/
+  else if (bpp == 24 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR &&
+          ((mask_rgb && byte_order == GDK_LSB_FIRST) ||
+           (mask_bgr && byte_order == GDK_MSB_FIRST)))
+    conv = gdk_rgb_convert_888_lsb;
+  else if (bpp == 24 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR &&
+          ((mask_rgb && byte_order == GDK_MSB_FIRST) ||
+           (mask_bgr && byte_order == GDK_LSB_FIRST)))
+    conv = gdk_rgb_convert_888_msb;
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  else if (bpp == 32 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR &&
+          (mask_rgb && byte_order == GDK_LSB_FIRST))
+    conv = gdk_rgb_convert_0888_br;
+  else if (bpp == 32 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR &&
+          (mask_rgb && byte_order == GDK_MSB_FIRST))
+    conv = gdk_rgb_convert_0888;
+  else if (bpp == 32 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR &&
+          (mask_bgr && byte_order == GDK_MSB_FIRST))
+    conv = gdk_rgb_convert_8880_br;
+#else
+  else if (bpp == 32 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR &&
+          (mask_rgb && byte_order == GDK_MSB_FIRST))
+    conv = gdk_rgb_convert_0888_br;
+  else if (bpp == 32 && (depth == 24 || depth == 32) && vtype == GDK_VISUAL_TRUE_COLOR &&
+          (mask_rgb && byte_order == GDK_LSB_FIRST))
+    conv = gdk_rgb_convert_0888;
+  else if (bpp == 32 && depth == 24 && vtype == GDK_VISUAL_TRUE_COLOR &&
+          (mask_bgr && byte_order == GDK_LSB_FIRST))
+    conv = gdk_rgb_convert_8880_br;
+#endif
+
+  else if (vtype == GDK_VISUAL_TRUE_COLOR && byte_order == GDK_LSB_FIRST)
+    {
+      conv = gdk_rgb_convert_truecolor_lsb;
+      conv_d = gdk_rgb_convert_truecolor_lsb_d;
+    }
+  else if (vtype == GDK_VISUAL_TRUE_COLOR && byte_order == GDK_MSB_FIRST)
+    {
+      conv = gdk_rgb_convert_truecolor_msb;
+      conv_d = gdk_rgb_convert_truecolor_msb_d;
+    }
+  else if (bpp == 8 && depth == 8 && (vtype == GDK_VISUAL_PSEUDO_COLOR
+#ifdef ENABLE_GRAYSCALE
+                                     || vtype == GDK_VISUAL_GRAYSCALE
+#endif
+                                     ))
+    {
+      image_info->dith_default = TRUE;
+      conv = gdk_rgb_convert_8;
+      if (vtype != GDK_VISUAL_GRAYSCALE)
+       {
+         if (image_info->nred_shades == 6 &&
+             image_info->ngreen_shades == 6 &&
+             image_info->nblue_shades == 6)
+           conv_d = gdk_rgb_convert_8_d666;
+         else
+           conv_d = gdk_rgb_convert_8_d;
+       }
+      conv_indexed = gdk_rgb_convert_8_indexed;
+      conv_gray = gdk_rgb_convert_gray_cmap;
+    }
+  else if (bpp == 8 && depth == 8 && (vtype == GDK_VISUAL_STATIC_GRAY
+#ifdef not_ENABLE_GRAYSCALE
+                                     || vtype == GDK_VISUAL_GRAYSCALE
+#endif
+                                     ))
+    {
+      conv = gdk_rgb_convert_gray8;
+      conv_gray = gdk_rgb_convert_gray8_gray;
+    }
+  else if (bpp == 8 && depth < 8 && depth >= 2 &&
+          (vtype == GDK_VISUAL_STATIC_GRAY
+           || vtype == GDK_VISUAL_GRAYSCALE))
+    {
+      conv = gdk_rgb_convert_gray4;
+      conv_d = gdk_rgb_convert_gray4_d;
+    }
+  else if (bpp == 8 && depth < 8 && depth >= 3)
+    {
+      conv = gdk_rgb_convert_4;
+    }
+  else if (bpp == 4 && depth <= 4 && depth >= 2 &&
+          (vtype == GDK_VISUAL_STATIC_GRAY
+           || vtype == GDK_VISUAL_GRAYSCALE))
+    {
+      conv = gdk_rgb_convert_gray4_pack;
+      conv_d = gdk_rgb_convert_gray4_d_pack;
+    }
+
+  if (conv_d == NULL)
+    conv_d = conv;
+
+  image_info->conv = conv;
+  image_info->conv_d = conv_d;
+
+  image_info->conv_32 = conv_32;
+  image_info->conv_32_d = conv_32_d;
+
+  image_info->conv_gray = conv_gray;
+  image_info->conv_gray_d = conv_gray_d;
+
+  image_info->conv_indexed = conv_indexed;
+  image_info->conv_indexed_d = conv_indexed_d;
+}
+
+static gint horiz_idx;
+static gint horiz_y = IMAGE_HEIGHT;
+static gint vert_idx;
+static gint vert_x = IMAGE_WIDTH;
+static gint tile_idx;
+static gint tile_x = IMAGE_WIDTH;
+static gint tile_y1 = IMAGE_HEIGHT;
+static gint tile_y2 = IMAGE_HEIGHT;
+
+#ifdef VERBOSE
+static gint sincelast;
+#endif
+
+/* Defining NO_FLUSH can cause inconsistent screen updates, but is useful
+   for performance evaluation. */
+
+#undef NO_FLUSH
+
+static gint
+gdk_rgb_alloc_scratch_image (void)
+{
+  if (static_image_idx == N_IMAGES)
+    {
+#ifndef NO_FLUSH
+      gdk_flush ();
+#endif
+#ifdef VERBOSE
+      g_print ("flush, %d puts since last flush\n", sincelast);
+      sincelast = 0;
+#endif
+      static_image_idx = 0;
+      horiz_y = IMAGE_HEIGHT;
+      vert_x = IMAGE_WIDTH;
+      tile_x = IMAGE_WIDTH;
+      tile_y1 = tile_y2 = IMAGE_HEIGHT;
+    }
+  return static_image_idx++;
+}
+
+static GdkImage *
+gdk_rgb_alloc_scratch (gint width, gint height, gint *x0, gint *y0)
+{
+  GdkImage *image;
+  gint idx;
+
+  if (width >= (IMAGE_WIDTH >> 1))
+    {
+      if (height >= (IMAGE_HEIGHT >> 1))
+       {
+         idx = gdk_rgb_alloc_scratch_image ();
+         *x0 = 0;
+         *y0 = 0;
+       }
+      else
+       {
+         if (height + horiz_y > IMAGE_HEIGHT)
+           {
+             horiz_idx = gdk_rgb_alloc_scratch_image ();
+             horiz_y = 0;
+           }
+         idx = horiz_idx;
+         *x0 = 0;
+         *y0 = horiz_y;
+         horiz_y += height;
+       }
+    }
+  else
+    {
+      if (height >= (IMAGE_HEIGHT >> 1))
+       {
+         if (width + vert_x > IMAGE_WIDTH)
+           {
+             vert_idx = gdk_rgb_alloc_scratch_image ();
+             vert_x = 0;
+           }
+         idx = vert_idx;
+         *x0 = vert_x;
+         *y0 = 0;
+         /* using 3 and -4 would be slightly more efficient on 32-bit machines
+            with > 1bpp displays */
+         vert_x += (width + 7) & -8;
+       }
+      else
+       {
+         if (width + tile_x > IMAGE_WIDTH)
+           {
+             tile_y1 = tile_y2;
+             tile_x = 0;
+           }
+         if (height + tile_y1 > IMAGE_HEIGHT)
+           {
+             tile_idx = gdk_rgb_alloc_scratch_image ();
+             tile_x = 0;
+             tile_y1 = 0;
+             tile_y2 = 0;
+           }
+         if (height + tile_y1 > tile_y2)
+           tile_y2 = height + tile_y1;
+         idx = tile_idx;
+         *x0 = tile_x;
+         *y0 = tile_y1;
+         tile_x += (width + 7) & -8;
+       }
+    }
+  image = static_image[idx];
+#ifdef VERBOSE
+  g_print ("index %d, x %d, y %d (%d x %d)\n", idx, *x0, *y0, width, height);
+  sincelast++;
+#endif
+  return image;
+}
+
+static void
+gdk_draw_rgb_image_core (GdkDrawable *drawable,
+                        GdkGC *gc,
+                        gint x,
+                        gint y,
+                        gint width,
+                        gint height,
+                        guchar *buf,
+                        gint pixstride,
+                        gint rowstride,
+                        GdkRgbConvFunc conv,
+                        GdkRgbCmap *cmap,
+                        gint xdith,
+                        gint ydith)
+{
+  gint y0, x0;
+  gint xs0, ys0;
+  GdkImage *image;
+  gint width1, height1;
+  guchar *buf_ptr;
+
+  if (image_info->bitmap)
+    {
+      if (image_info->own_gc == NULL)
+       {
+         GdkColor color;
+
+         image_info->own_gc = gdk_gc_new (drawable);
+         gdk_color_white (image_info->cmap, &color);
+         gdk_gc_set_foreground (image_info->own_gc, &color);
+         gdk_color_black (image_info->cmap, &color);
+         gdk_gc_set_background (image_info->own_gc, &color);
+       }
+      gc = image_info->own_gc;
+    }
+  for (y0 = 0; y0 < height; y0 += IMAGE_HEIGHT)
+    {
+      height1 = MIN (height - y0, IMAGE_HEIGHT);
+      for (x0 = 0; x0 < width; x0 += IMAGE_WIDTH)
+       {
+         width1 = MIN (width - x0, IMAGE_WIDTH);
+         buf_ptr = buf + y0 * rowstride + x0 * pixstride;
+
+         image = gdk_rgb_alloc_scratch (width1, height1, &xs0, &ys0);
+
+         conv (image, xs0, ys0, width1, height1, buf_ptr, rowstride,
+               x + x0 + xdith, y + y0 + ydith, cmap);
+
+#ifndef DONT_ACTUALLY_DRAW
+         gdk_draw_image (drawable, gc,
+                         image, xs0, ys0, x + x0, y + y0, width1, height1);
+#endif
+       }
+    }
+}
+
+
+void
+gdk_draw_rgb_image (GdkDrawable *drawable,
+                   GdkGC *gc,
+                   gint x,
+                   gint y,
+                   gint width,
+                   gint height,
+                   GdkRgbDither dith,
+                   guchar *rgb_buf,
+                   gint rowstride)
+{
+  if (dith == GDK_RGB_DITHER_NONE || (dith == GDK_RGB_DITHER_NORMAL &&
+                                     !image_info->dith_default))
+    gdk_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                            rgb_buf, 3, rowstride, image_info->conv, NULL,
+                            0, 0);
+  else
+    gdk_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                            rgb_buf, 3, rowstride, image_info->conv_d, NULL,
+                            0, 0);
+}
+
+void
+gdk_draw_rgb_image_dithalign (GdkDrawable *drawable,
+                             GdkGC *gc,
+                             gint x,
+                             gint y,
+                             gint width,
+                             gint height,
+                             GdkRgbDither dith,
+                             guchar *rgb_buf,
+                             gint rowstride,
+                             gint xdith,
+                             gint ydith)
+{
+  if (dith == GDK_RGB_DITHER_NONE || (dith == GDK_RGB_DITHER_NORMAL &&
+                                     !image_info->dith_default))
+    gdk_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                            rgb_buf, 3, rowstride, image_info->conv, NULL,
+                            xdith, ydith);
+  else
+    gdk_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                            rgb_buf, 3, rowstride, image_info->conv_d, NULL,
+                            xdith, ydith);
+}
+
+void
+gdk_draw_rgb_32_image (GdkDrawable *drawable,
+                      GdkGC *gc,
+                      gint x,
+                      gint y,
+                      gint width,
+                      gint height,
+                      GdkRgbDither dith,
+                      guchar *buf,
+                      gint rowstride)
+{
+  if (dith == GDK_RGB_DITHER_NONE || (dith == GDK_RGB_DITHER_NORMAL &&
+                                     !image_info->dith_default))
+    gdk_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                            buf, 4, rowstride,
+                            image_info->conv_32, NULL, 0, 0);
+  else
+    gdk_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                            buf, 4, rowstride,
+                            image_info->conv_32_d, NULL, 0, 0);
+}
+
+static void
+gdk_rgb_make_gray_cmap (GdkRgbInfo *info)
+{
+  guint32 rgb[256];
+  gint i;
+
+  for (i = 0; i < 256; i++)
+    rgb[i] = (i << 16)  | (i << 8) | i;
+  info->gray_cmap = gdk_rgb_cmap_new (rgb, 256);
+}
+
+void
+gdk_draw_gray_image (GdkDrawable *drawable,
+                    GdkGC *gc,
+                    gint x,
+                    gint y,
+                    gint width,
+                    gint height,
+                    GdkRgbDither dith,
+                    guchar *buf,
+                    gint rowstride)
+{
+  if (image_info->bpp == 1 &&
+      image_info->gray_cmap == NULL &&
+      (image_info->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
+       image_info->visual->type == GDK_VISUAL_GRAYSCALE))
+    gdk_rgb_make_gray_cmap (image_info);
+  
+  if (dith == GDK_RGB_DITHER_NONE || (dith == GDK_RGB_DITHER_NORMAL &&
+                                     !image_info->dith_default))
+    gdk_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                            buf, 1, rowstride,
+                            image_info->conv_gray, NULL, 0, 0);
+  else
+    gdk_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                            buf, 1, rowstride,
+                            image_info->conv_gray_d, NULL, 0, 0);
+}
+
+GdkRgbCmap *
+gdk_rgb_cmap_new (guint32 *colors, gint n_colors)
+{
+  GdkRgbCmap *cmap;
+  int i, j;
+  guint32 rgb;
+
+  g_return_val_if_fail (n_colors >= 0, NULL);
+  g_return_val_if_fail (n_colors <= 256, NULL);
+  cmap = g_new (GdkRgbCmap, 1);
+  memcpy (cmap->colors, colors, n_colors * sizeof(guint32));
+  if (image_info->bpp == 1 &&
+      (image_info->visual->type == GDK_VISUAL_PSEUDO_COLOR ||
+       image_info->visual->type == GDK_VISUAL_GRAYSCALE))
+    for (i = 0; i < n_colors; i++)
+      {
+       rgb = colors[i];
+       j = ((rgb & 0xf00000) >> 12) |
+                  ((rgb & 0xf000) >> 8) |
+                  ((rgb & 0xf0) >> 4);
+#ifdef VERBOSE
+       g_print ("%d %x %x %d\n", i, j, colorcube[j]);
+#endif
+       cmap->lut[i] = colorcube[j];
+      }
+  return cmap;
+}
+
+void
+gdk_rgb_cmap_free (GdkRgbCmap *cmap)
+{
+  g_free (cmap);
+}
+
+void
+gdk_draw_indexed_image (GdkDrawable *drawable,
+                       GdkGC *gc,
+                       gint x,
+                       gint y,
+                       gint width,
+                       gint height,
+                       GdkRgbDither dith,
+                       guchar *buf,
+                       gint rowstride,
+                       GdkRgbCmap *cmap)
+{
+  if (dith == GDK_RGB_DITHER_NONE || (dith == GDK_RGB_DITHER_NORMAL &&
+                                     !image_info->dith_default))
+    gdk_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                            buf, 1, rowstride,
+                            image_info->conv_indexed, cmap, 0, 0);
+  else
+    gdk_draw_rgb_image_core (drawable, gc, x, y, width, height,
+                            buf, 1, rowstride,
+                            image_info->conv_indexed_d, cmap, 0, 0);
+}
+
+gboolean
+gdk_rgb_ditherable (void)
+{
+  return (image_info->conv != image_info->conv_d);
+}
+
+GdkColormap *
+gdk_rgb_get_cmap (void)
+{
+  gdk_rgb_init ();
+  return image_info->cmap;
+}
+
+GdkVisual *
+gdk_rgb_get_visual (void)
+{
+  gdk_rgb_init ();
+  return image_info->visual;
+}
diff --git a/gdk/win32/gdkselection-win32.c b/gdk/win32/gdkselection-win32.c
new file mode 100644 (file)
index 0000000..2c91ba2
--- /dev/null
@@ -0,0 +1,392 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "gdk.h"
+#include "gdkx.h"
+#include "gdkprivate.h"
+
+/* We emulate the GDK_SELECTION window properties by storing
+ * it's data in a per-window hashtable.
+ */
+
+typedef struct {
+  guchar *data;
+  gint length;
+  gint format;
+  GdkAtom type;
+} GdkSelProp;
+
+static GHashTable *sel_prop_table = NULL;
+
+void
+gdk_selection_init (void)
+{
+  if (sel_prop_table == NULL)
+    sel_prop_table = g_hash_table_new (g_int_hash, g_int_equal);
+}
+
+void
+gdk_sel_prop_store (GdkWindow *owner,
+                   GdkAtom    type,
+                   gint       format,
+                   guchar    *data,
+                   gint       length)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *) owner;
+  GdkSelProp *prop;
+
+  prop = g_hash_table_lookup (sel_prop_table, &private->xwindow);
+  if (prop != NULL)
+    {
+      g_free (prop->data);
+      g_hash_table_remove (sel_prop_table, &private->xwindow);
+    }
+  prop = g_new (GdkSelProp, 1);
+  prop->data = data;
+  prop->length = length;
+  prop->format = format;
+  prop->type = type;
+  g_hash_table_insert (sel_prop_table, &private->xwindow, prop);
+}
+  
+
+gint
+gdk_selection_owner_set (GdkWindow *owner,
+                        GdkAtom    selection,
+                        guint32    time,
+                        gint       send_event)
+{
+  GdkWindowPrivate *private;
+  gchar *sel_name;
+  HWND xwindow;
+
+  private = (GdkWindowPrivate *) owner;
+
+  GDK_NOTE (SELECTION,
+           (sel_name = gdk_atom_name (selection),
+            g_print ("gdk_selection_owner_set: %#x %#x (%s)\n",
+                     (private ? private->xwindow : 0),
+                     selection, sel_name),
+            g_free (sel_name)));
+
+  if (selection != gdk_clipboard_atom)
+    return FALSE;
+
+  if (owner != NULL)
+    xwindow = private->xwindow;
+  else
+    xwindow = NULL;
+
+  if (!OpenClipboard (xwindow))
+    {
+      g_warning ("gdk_selection_owner_set: OpenClipboard failed");
+      return FALSE;
+    }
+  if (!EmptyClipboard ())
+    {
+      g_warning ("gdk_selection_owner_set: EmptyClipboard failed");
+      CloseClipboard ();
+      return FALSE;
+    }
+#if 0
+  /* No delayed rendering */
+  if (xwindow != NULL)
+    SetClipboardData (CF_TEXT, NULL);
+#endif
+  if (!CloseClipboard ())
+    {
+      g_warning ("gdk_selection_owner_set: CloseClipboard failed");
+      return FALSE;
+    }
+  if (owner != NULL)
+    {
+      /* Send ourselves an ersatz selection request message so that
+       * gdk_property_change will be called to store the clipboard data.
+       */
+      SendMessage (private->xwindow, gdk_selection_request_msg,
+                  selection, 0);
+    }
+
+  return TRUE;
+}
+
+GdkWindow*
+gdk_selection_owner_get (GdkAtom selection)
+{
+  GdkWindow *window;
+  GdkWindowPrivate *private;
+  gchar *sel_name;
+
+  if (selection != gdk_clipboard_atom)
+    window = NULL;
+  else
+    window = gdk_window_lookup (GetClipboardOwner ());
+
+  private = (GdkWindowPrivate *) window;
+
+  GDK_NOTE (SELECTION,
+           (sel_name = gdk_atom_name (selection),
+            g_print ("gdk_selection_owner_get: %#x (%s) = %#x\n",
+                     selection, sel_name,
+                     (private ? private->xwindow : 0)),
+            g_free (sel_name)));
+
+  return window;
+}
+
+void
+gdk_selection_convert (GdkWindow *requestor,
+                      GdkAtom    selection,
+                      GdkAtom    target,
+                      guint32    time)
+{
+  GdkWindowPrivate *private;
+  HGLOBAL hdata;
+  GdkSelProp *prop;
+  guchar *ptr, *data, *datap, *p;
+  guint i, length, slength;
+  gchar *sel_name, *tgt_name;
+
+  g_return_if_fail (requestor != NULL);
+
+  private = (GdkWindowPrivate*) requestor;
+
+  GDK_NOTE (SELECTION,
+           (sel_name = gdk_atom_name (selection),
+            tgt_name = gdk_atom_name (target),
+            g_print ("gdk_selection_convert: %#x %#x (%s) %#x (%s)\n",
+                     private->xwindow, selection, sel_name, target, tgt_name),
+            g_free (sel_name),
+            g_free (tgt_name)));
+
+  if (selection == gdk_clipboard_atom)
+    {
+      /* Converting the CLIPBOARD selection means he wants the
+       * contents of the clipboard. Get the clipboard data,
+       * and store it for later.
+       */
+      if (!OpenClipboard (private->xwindow))
+       {
+         g_warning ("gdk_selection_convert: OpenClipboard failed");
+         return;
+       }
+
+      if ((hdata = GetClipboardData (CF_TEXT)) != NULL)
+       {
+         if ((ptr = GlobalLock (hdata)) != NULL)
+           {
+             length = GlobalSize (hdata);
+             
+             GDK_NOTE (SELECTION, g_print ("...got data: %d bytes: %.10s\n",
+                                           length, ptr));
+             
+             slength = 0;
+             p = ptr;
+             for (i = 0; i < length; i++)
+               {
+                 if (*p == '\0')
+                   break;
+                 else if (*p != '\r')
+                   slength++;
+                 p++;
+               }
+             
+             data = datap = g_malloc (slength + 1);
+             p = ptr;
+             for (i = 0; i < length; i++)
+               {
+                 if (*p == '\0')
+                   break;
+                 else if (*p != '\r')
+                   *datap++ = *p;
+                 p++;
+               }
+             *datap++ = '\0';
+             gdk_sel_prop_store (requestor, GDK_TARGET_STRING, 8,
+                                 data, strlen (data) + 1);
+             
+             GlobalUnlock (hdata);
+           }
+       }
+      CloseClipboard ();
+
+
+      /* Send ourselves an ersatz selection notify message so that we actually
+       * fetch the data.
+       */
+      SendMessage (private->xwindow, gdk_selection_notify_msg, selection, target);
+    }
+  else if (selection == gdk_win32_dropfiles_atom)
+    {
+      /* This means he wants the names of the dropped files.
+       * gdk_dropfiles_filter already has stored the text/uri-list
+       * data, tempoarily on gdk_root_parent's selection "property".
+       */
+      GdkSelProp *prop;
+
+      prop = g_hash_table_lookup (sel_prop_table, &gdk_root_parent.xwindow);
+
+      if (prop != NULL)
+       {
+         g_hash_table_remove (sel_prop_table, &gdk_root_parent.xwindow);
+         gdk_sel_prop_store (requestor, prop->type, prop->format,
+                             prop->data, prop->length);
+         g_free (prop);
+         SendMessage (private->xwindow, gdk_selection_notify_msg, selection, target);
+       }
+    }
+  else
+    {
+      g_warning ("gdk_selection_convert: General case not implemented");
+    }
+}
+
+gint
+gdk_selection_property_get (GdkWindow  *requestor,
+                           guchar    **data,
+                           GdkAtom    *ret_type,
+                           gint       *ret_format)
+{
+  GdkWindowPrivate *private;
+  GdkSelProp *prop;
+
+  g_return_val_if_fail (requestor != NULL, 0);
+
+  private = (GdkWindowPrivate*) requestor;
+  if (private->destroyed)
+    return 0;
+  
+  GDK_NOTE (SELECTION, g_print ("gdk_selection_property_get: %#x\n",
+                               private->xwindow));
+
+  prop = g_hash_table_lookup (sel_prop_table, &private->xwindow);
+
+  if (prop == NULL)
+    {
+      *data = NULL;
+      return 0;
+    }
+  *data = g_malloc (prop->length);
+  if (prop->length > 0)
+    memmove (*data, prop->data, prop->length);
+  if (ret_type)
+    *ret_type = prop->type;
+  if (ret_format)
+    *ret_format = prop->format;
+
+  return prop->length;
+}
+
+void
+gdk_selection_property_delete (GdkWindowPrivate *private)
+{
+  GdkSelProp *prop;
+  
+  prop = g_hash_table_lookup (sel_prop_table, &private->xwindow);
+  if (prop != NULL)
+    {
+      g_free (prop->data);
+      g_hash_table_remove (sel_prop_table, &private->xwindow);
+    }
+  else
+    g_warning ("huh?");
+}
+
+void
+gdk_selection_send_notify (guint32  requestor,
+                          GdkAtom  selection,
+                          GdkAtom  target,
+                          GdkAtom  property,
+                          guint32  time)
+{
+  gchar *sel_name, *tgt_name, *prop_name;
+
+  GDK_NOTE (SELECTION,
+           (sel_name = gdk_atom_name (selection),
+            tgt_name = gdk_atom_name (target),
+            prop_name = gdk_atom_name (property),
+            g_print ("gdk_selection_send_notify: %#x %#x (%s) %#x (%s) %#x (%s)\n",
+                     requestor,
+                     selection, sel_name,
+                     target, tgt_name,
+                     property, prop_name),
+            g_free (sel_name),
+            g_free (tgt_name),
+            g_free (prop_name)));
+
+  /* Send ourselves a selection clear message sot that gtk thinks we doen't
+   * have the selection, and will claim it anew when needed, and
+   * we thus get a chance to store data in the Windows clipboard.
+   * Otherwise, if a gtkeditable does a copy to clipboard several times
+   * only the first one actually gets copied to the Windows clipboard,
+   * as only he first one causes a call to gdk_property_change.
+   */
+
+  SendMessage ((HWND) requestor, gdk_selection_clear_msg, selection, 0);
+}
+
+gint
+gdk_text_property_to_text_list (GdkAtom  encoding,
+                               gint     format, 
+                               guchar  *text,
+                               gint     length,
+                               gchar ***list)
+{
+  GDK_NOTE (SELECTION,
+           g_print ("gdk_text_property_to_text_list not implemented\n"));
+  
+  return 0;
+}
+
+void
+gdk_free_text_list (gchar **list)
+{
+  g_return_if_fail (list != NULL);
+
+  /* ??? */
+}
+
+gint
+gdk_string_to_compound_text (gchar   *str,
+                            GdkAtom *encoding,
+                            gint    *format,
+                            guchar **ctext,
+                            gint    *length)
+{
+  g_warning ("gdk_string_to_compound_text: Not implemented");
+
+  return 0;
+}
+
+void
+gdk_free_compound_text (guchar *ctext)
+{
+  g_warning ("gdk_free_compound_text: Not implemented");
+}
diff --git a/gdk/win32/gdkselection.c b/gdk/win32/gdkselection.c
new file mode 100644 (file)
index 0000000..2c91ba2
--- /dev/null
@@ -0,0 +1,392 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "gdk.h"
+#include "gdkx.h"
+#include "gdkprivate.h"
+
+/* We emulate the GDK_SELECTION window properties by storing
+ * it's data in a per-window hashtable.
+ */
+
+typedef struct {
+  guchar *data;
+  gint length;
+  gint format;
+  GdkAtom type;
+} GdkSelProp;
+
+static GHashTable *sel_prop_table = NULL;
+
+void
+gdk_selection_init (void)
+{
+  if (sel_prop_table == NULL)
+    sel_prop_table = g_hash_table_new (g_int_hash, g_int_equal);
+}
+
+void
+gdk_sel_prop_store (GdkWindow *owner,
+                   GdkAtom    type,
+                   gint       format,
+                   guchar    *data,
+                   gint       length)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *) owner;
+  GdkSelProp *prop;
+
+  prop = g_hash_table_lookup (sel_prop_table, &private->xwindow);
+  if (prop != NULL)
+    {
+      g_free (prop->data);
+      g_hash_table_remove (sel_prop_table, &private->xwindow);
+    }
+  prop = g_new (GdkSelProp, 1);
+  prop->data = data;
+  prop->length = length;
+  prop->format = format;
+  prop->type = type;
+  g_hash_table_insert (sel_prop_table, &private->xwindow, prop);
+}
+  
+
+gint
+gdk_selection_owner_set (GdkWindow *owner,
+                        GdkAtom    selection,
+                        guint32    time,
+                        gint       send_event)
+{
+  GdkWindowPrivate *private;
+  gchar *sel_name;
+  HWND xwindow;
+
+  private = (GdkWindowPrivate *) owner;
+
+  GDK_NOTE (SELECTION,
+           (sel_name = gdk_atom_name (selection),
+            g_print ("gdk_selection_owner_set: %#x %#x (%s)\n",
+                     (private ? private->xwindow : 0),
+                     selection, sel_name),
+            g_free (sel_name)));
+
+  if (selection != gdk_clipboard_atom)
+    return FALSE;
+
+  if (owner != NULL)
+    xwindow = private->xwindow;
+  else
+    xwindow = NULL;
+
+  if (!OpenClipboard (xwindow))
+    {
+      g_warning ("gdk_selection_owner_set: OpenClipboard failed");
+      return FALSE;
+    }
+  if (!EmptyClipboard ())
+    {
+      g_warning ("gdk_selection_owner_set: EmptyClipboard failed");
+      CloseClipboard ();
+      return FALSE;
+    }
+#if 0
+  /* No delayed rendering */
+  if (xwindow != NULL)
+    SetClipboardData (CF_TEXT, NULL);
+#endif
+  if (!CloseClipboard ())
+    {
+      g_warning ("gdk_selection_owner_set: CloseClipboard failed");
+      return FALSE;
+    }
+  if (owner != NULL)
+    {
+      /* Send ourselves an ersatz selection request message so that
+       * gdk_property_change will be called to store the clipboard data.
+       */
+      SendMessage (private->xwindow, gdk_selection_request_msg,
+                  selection, 0);
+    }
+
+  return TRUE;
+}
+
+GdkWindow*
+gdk_selection_owner_get (GdkAtom selection)
+{
+  GdkWindow *window;
+  GdkWindowPrivate *private;
+  gchar *sel_name;
+
+  if (selection != gdk_clipboard_atom)
+    window = NULL;
+  else
+    window = gdk_window_lookup (GetClipboardOwner ());
+
+  private = (GdkWindowPrivate *) window;
+
+  GDK_NOTE (SELECTION,
+           (sel_name = gdk_atom_name (selection),
+            g_print ("gdk_selection_owner_get: %#x (%s) = %#x\n",
+                     selection, sel_name,
+                     (private ? private->xwindow : 0)),
+            g_free (sel_name)));
+
+  return window;
+}
+
+void
+gdk_selection_convert (GdkWindow *requestor,
+                      GdkAtom    selection,
+                      GdkAtom    target,
+                      guint32    time)
+{
+  GdkWindowPrivate *private;
+  HGLOBAL hdata;
+  GdkSelProp *prop;
+  guchar *ptr, *data, *datap, *p;
+  guint i, length, slength;
+  gchar *sel_name, *tgt_name;
+
+  g_return_if_fail (requestor != NULL);
+
+  private = (GdkWindowPrivate*) requestor;
+
+  GDK_NOTE (SELECTION,
+           (sel_name = gdk_atom_name (selection),
+            tgt_name = gdk_atom_name (target),
+            g_print ("gdk_selection_convert: %#x %#x (%s) %#x (%s)\n",
+                     private->xwindow, selection, sel_name, target, tgt_name),
+            g_free (sel_name),
+            g_free (tgt_name)));
+
+  if (selection == gdk_clipboard_atom)
+    {
+      /* Converting the CLIPBOARD selection means he wants the
+       * contents of the clipboard. Get the clipboard data,
+       * and store it for later.
+       */
+      if (!OpenClipboard (private->xwindow))
+       {
+         g_warning ("gdk_selection_convert: OpenClipboard failed");
+         return;
+       }
+
+      if ((hdata = GetClipboardData (CF_TEXT)) != NULL)
+       {
+         if ((ptr = GlobalLock (hdata)) != NULL)
+           {
+             length = GlobalSize (hdata);
+             
+             GDK_NOTE (SELECTION, g_print ("...got data: %d bytes: %.10s\n",
+                                           length, ptr));
+             
+             slength = 0;
+             p = ptr;
+             for (i = 0; i < length; i++)
+               {
+                 if (*p == '\0')
+                   break;
+                 else if (*p != '\r')
+                   slength++;
+                 p++;
+               }
+             
+             data = datap = g_malloc (slength + 1);
+             p = ptr;
+             for (i = 0; i < length; i++)
+               {
+                 if (*p == '\0')
+                   break;
+                 else if (*p != '\r')
+                   *datap++ = *p;
+                 p++;
+               }
+             *datap++ = '\0';
+             gdk_sel_prop_store (requestor, GDK_TARGET_STRING, 8,
+                                 data, strlen (data) + 1);
+             
+             GlobalUnlock (hdata);
+           }
+       }
+      CloseClipboard ();
+
+
+      /* Send ourselves an ersatz selection notify message so that we actually
+       * fetch the data.
+       */
+      SendMessage (private->xwindow, gdk_selection_notify_msg, selection, target);
+    }
+  else if (selection == gdk_win32_dropfiles_atom)
+    {
+      /* This means he wants the names of the dropped files.
+       * gdk_dropfiles_filter already has stored the text/uri-list
+       * data, tempoarily on gdk_root_parent's selection "property".
+       */
+      GdkSelProp *prop;
+
+      prop = g_hash_table_lookup (sel_prop_table, &gdk_root_parent.xwindow);
+
+      if (prop != NULL)
+       {
+         g_hash_table_remove (sel_prop_table, &gdk_root_parent.xwindow);
+         gdk_sel_prop_store (requestor, prop->type, prop->format,
+                             prop->data, prop->length);
+         g_free (prop);
+         SendMessage (private->xwindow, gdk_selection_notify_msg, selection, target);
+       }
+    }
+  else
+    {
+      g_warning ("gdk_selection_convert: General case not implemented");
+    }
+}
+
+gint
+gdk_selection_property_get (GdkWindow  *requestor,
+                           guchar    **data,
+                           GdkAtom    *ret_type,
+                           gint       *ret_format)
+{
+  GdkWindowPrivate *private;
+  GdkSelProp *prop;
+
+  g_return_val_if_fail (requestor != NULL, 0);
+
+  private = (GdkWindowPrivate*) requestor;
+  if (private->destroyed)
+    return 0;
+  
+  GDK_NOTE (SELECTION, g_print ("gdk_selection_property_get: %#x\n",
+                               private->xwindow));
+
+  prop = g_hash_table_lookup (sel_prop_table, &private->xwindow);
+
+  if (prop == NULL)
+    {
+      *data = NULL;
+      return 0;
+    }
+  *data = g_malloc (prop->length);
+  if (prop->length > 0)
+    memmove (*data, prop->data, prop->length);
+  if (ret_type)
+    *ret_type = prop->type;
+  if (ret_format)
+    *ret_format = prop->format;
+
+  return prop->length;
+}
+
+void
+gdk_selection_property_delete (GdkWindowPrivate *private)
+{
+  GdkSelProp *prop;
+  
+  prop = g_hash_table_lookup (sel_prop_table, &private->xwindow);
+  if (prop != NULL)
+    {
+      g_free (prop->data);
+      g_hash_table_remove (sel_prop_table, &private->xwindow);
+    }
+  else
+    g_warning ("huh?");
+}
+
+void
+gdk_selection_send_notify (guint32  requestor,
+                          GdkAtom  selection,
+                          GdkAtom  target,
+                          GdkAtom  property,
+                          guint32  time)
+{
+  gchar *sel_name, *tgt_name, *prop_name;
+
+  GDK_NOTE (SELECTION,
+           (sel_name = gdk_atom_name (selection),
+            tgt_name = gdk_atom_name (target),
+            prop_name = gdk_atom_name (property),
+            g_print ("gdk_selection_send_notify: %#x %#x (%s) %#x (%s) %#x (%s)\n",
+                     requestor,
+                     selection, sel_name,
+                     target, tgt_name,
+                     property, prop_name),
+            g_free (sel_name),
+            g_free (tgt_name),
+            g_free (prop_name)));
+
+  /* Send ourselves a selection clear message sot that gtk thinks we doen't
+   * have the selection, and will claim it anew when needed, and
+   * we thus get a chance to store data in the Windows clipboard.
+   * Otherwise, if a gtkeditable does a copy to clipboard several times
+   * only the first one actually gets copied to the Windows clipboard,
+   * as only he first one causes a call to gdk_property_change.
+   */
+
+  SendMessage ((HWND) requestor, gdk_selection_clear_msg, selection, 0);
+}
+
+gint
+gdk_text_property_to_text_list (GdkAtom  encoding,
+                               gint     format, 
+                               guchar  *text,
+                               gint     length,
+                               gchar ***list)
+{
+  GDK_NOTE (SELECTION,
+           g_print ("gdk_text_property_to_text_list not implemented\n"));
+  
+  return 0;
+}
+
+void
+gdk_free_text_list (gchar **list)
+{
+  g_return_if_fail (list != NULL);
+
+  /* ??? */
+}
+
+gint
+gdk_string_to_compound_text (gchar   *str,
+                            GdkAtom *encoding,
+                            gint    *format,
+                            guchar **ctext,
+                            gint    *length)
+{
+  g_warning ("gdk_string_to_compound_text: Not implemented");
+
+  return 0;
+}
+
+void
+gdk_free_compound_text (guchar *ctext)
+{
+  g_warning ("gdk_free_compound_text: Not implemented");
+}
diff --git a/gdk/win32/gdktypes.h b/gdk/win32/gdktypes.h
new file mode 100644 (file)
index 0000000..4eeb65c
--- /dev/null
@@ -0,0 +1,1279 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GDK_TYPES_H__
+#define __GDK_TYPES_H__
+
+
+/* GDK uses "glib". (And so does GTK).
+ */
+#include <glib.h>
+
+#ifdef NATIVE_WIN32
+#ifdef COMPILING_GDK
+#define GDKVAR __declspec(dllexport)
+#else
+#define GDKVAR extern __declspec(dllimport)
+#endif
+#else
+#define GDKVAR extern
+#endif
+
+#define GDK_NONE            0L
+#define GDK_CURRENT_TIME     0L
+#define GDK_PARENT_RELATIVE  1L
+
+/* special deviceid for core pointer events */
+#define GDK_CORE_POINTER 0xfedc
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* Type definitions for the basic structures.
+ */
+
+typedef gulong                       GdkAtom;
+typedef struct _GdkColor             GdkColor;
+typedef struct _GdkColormap          GdkColormap;
+typedef struct _GdkVisual            GdkVisual;
+typedef struct _GdkWindowAttr        GdkWindowAttr;
+typedef struct _GdkWindow            GdkWindow;
+typedef struct _GdkWindow            GdkPixmap;
+typedef struct _GdkWindow            GdkBitmap;
+typedef struct _GdkWindow            GdkDrawable;
+typedef struct _GdkGeometry           GdkGeometry;
+typedef struct _GdkImage             GdkImage;
+typedef struct _GdkGCValues          GdkGCValues;
+typedef struct _GdkGC                GdkGC;
+typedef struct _GdkPoint             GdkPoint;
+typedef struct _GdkRectangle         GdkRectangle;
+typedef struct _GdkSegment           GdkSegment;
+typedef struct _GdkFont                      GdkFont;
+typedef struct _GdkCursor            GdkCursor;
+typedef struct _GdkColorContextDither GdkColorContextDither;
+typedef struct _GdkColorContext              GdkColorContext;
+typedef struct _GdkDragContext        GdkDragContext;
+
+typedef struct _GdkEventAny        GdkEventAny;
+typedef struct _GdkEventExpose     GdkEventExpose;
+typedef struct _GdkEventNoExpose    GdkEventNoExpose;
+typedef struct _GdkEventVisibility  GdkEventVisibility;
+typedef struct _GdkEventMotion     GdkEventMotion;
+typedef struct _GdkEventButton     GdkEventButton;
+typedef struct _GdkEventKey        GdkEventKey;
+typedef struct _GdkEventFocus      GdkEventFocus;
+typedef struct _GdkEventCrossing    GdkEventCrossing;
+typedef struct _GdkEventConfigure   GdkEventConfigure;
+typedef struct _GdkEventProperty    GdkEventProperty;
+typedef struct _GdkEventSelection   GdkEventSelection;
+typedef struct _GdkEventProximity   GdkEventProximity;
+typedef struct _GdkEventClient     GdkEventClient;
+
+typedef struct _GdkEventDND         GdkEventDND;
+
+typedef union  _GdkEvent           GdkEvent;
+
+typedef struct _GdkDeviceKey       GdkDeviceKey;
+typedef struct _GdkDeviceInfo      GdkDeviceInfo;
+typedef struct _GdkTimeCoord       GdkTimeCoord;
+typedef struct _GdkRegion          GdkRegion;
+typedef void (*GdkEventFunc) (GdkEvent *event,
+                             gpointer  data);
+
+typedef struct _GdkIC               GdkIC;
+typedef struct _GdkICAttr          GdkICAttr;
+
+typedef guint32                            GdkWChar;
+
+/* Types of windows.
+ *   Root: There is only 1 root window and it is initialized
+ *        at startup. Creating a window of type GDK_WINDOW_ROOT
+ *        is an error.
+ *   Toplevel: Windows which interact with the window manager.
+ *   Child: Windows which are children of some other type of window.
+ *         (Any other type of window). Most windows are child windows.
+ *   Dialog: A special kind of toplevel window which interacts with
+ *          the window manager slightly differently than a regular
+ *          toplevel window. Dialog windows should be used for any
+ *          transient window.
+ *   Pixmap: Pixmaps are really just another kind of window which
+ *          doesn't actually appear on the screen. It can't have
+ *          children, either and is really just a convenience so
+ *          that the drawing functions can work on both windows
+ *          and pixmaps transparently. (ie. You shouldn't pass a
+ *          pixmap to any procedure which accepts a window with the
+ *          exception of the drawing functions).
+ *   Foreign: A window that actually belongs to another application
+ */
+typedef enum
+{
+  GDK_WINDOW_ROOT,
+  GDK_WINDOW_TOPLEVEL,
+  GDK_WINDOW_CHILD,
+  GDK_WINDOW_DIALOG,
+  GDK_WINDOW_TEMP,
+  GDK_WINDOW_PIXMAP,
+  GDK_WINDOW_FOREIGN
+} GdkWindowType;
+
+/* Classes of windows.
+ *   InputOutput: Almost every window should be of this type. Such windows
+ *               receive events and are also displayed on screen.
+ *   InputOnly: Used only in special circumstances when events need to be
+ *             stolen from another window or windows. Input only windows
+ *             have no visible output, so they are handy for placing over
+ *             top of a group of windows in order to grab the events (or
+ *             filter the events) from those windows.
+ */
+typedef enum
+{
+  GDK_INPUT_OUTPUT,
+  GDK_INPUT_ONLY
+} GdkWindowClass;
+
+/* Types of images.
+ *   Normal: Normal X image type. These are slow as they involve passing
+ *          the entire image through the X connection each time a draw
+ *          request is required.
+ *   Shared: Shared memory X image type. These are fast as the X server
+ *          and the program actually use the same piece of memory. They
+ *          should be used with care though as there is the possibility
+ *          for both the X server and the program to be reading/writing
+ *          the image simultaneously and producing undesired results.
+ *   Shared Pixmap: Also a shared memory image, which also has a
+ *          pixmap using the same memory.
+ */
+typedef enum
+{
+  GDK_IMAGE_NORMAL,
+  GDK_IMAGE_SHARED,
+  GDK_IMAGE_FASTEST,
+  GDK_IMAGE_SHARED_PIXMAP
+} GdkImageType;
+
+/* Types of visuals.
+ *   StaticGray:
+ *   Grayscale:
+ *   StaticColor:
+ *   PseudoColor:
+ *   TrueColor:
+ *   DirectColor:
+ */
+typedef enum
+{
+  GDK_VISUAL_STATIC_GRAY,
+  GDK_VISUAL_GRAYSCALE,
+  GDK_VISUAL_STATIC_COLOR,
+  GDK_VISUAL_PSEUDO_COLOR,
+  GDK_VISUAL_TRUE_COLOR,
+  GDK_VISUAL_DIRECT_COLOR
+} GdkVisualType;
+
+/* Types of font.
+ *   GDK_FONT_FONT: the font is an XFontStruct.
+ *   GDK_FONT_FONTSET: the font is an XFontSet used for I18N.
+ */
+typedef enum
+{
+  GDK_FONT_FONT,
+  GDK_FONT_FONTSET
+} GdkFontType;
+
+/* Window attribute mask values.
+ *   GDK_WA_TITLE: The "title" field is valid.
+ *   GDK_WA_X: The "x" field is valid.
+ *   GDK_WA_Y: The "y" field is valid.
+ *   GDK_WA_CURSOR: The "cursor" field is valid.
+ *   GDK_WA_COLORMAP: The "colormap" field is valid.
+ *   GDK_WA_VISUAL: The "visual" field is valid.
+ */
+typedef enum
+{
+  GDK_WA_TITLE   = 1 << 1,
+  GDK_WA_X       = 1 << 2,
+  GDK_WA_Y       = 1 << 3,
+  GDK_WA_CURSOR          = 1 << 4,
+  GDK_WA_COLORMAP = 1 << 5,
+  GDK_WA_VISUAL          = 1 << 6,
+  GDK_WA_WMCLASS  = 1 << 7,
+  GDK_WA_NOREDIR  = 1 << 8
+} GdkWindowAttributesType;
+
+/* Size restriction enumeration.
+ */
+typedef enum
+{
+  GDK_HINT_POS       = 1 << 0,
+  GDK_HINT_MIN_SIZE   = 1 << 1,
+  GDK_HINT_MAX_SIZE   = 1 << 2,
+  GDK_HINT_BASE_SIZE  = 1 << 3,
+  GDK_HINT_ASPECT     = 1 << 4,
+  GDK_HINT_RESIZE_INC = 1 << 5
+} GdkWindowHints;
+
+/* GC function types.
+ *   Copy: Overwrites destination pixels with the source pixels.
+ *   Invert: Inverts the destination pixels.
+ *   Xor: Xor's the destination pixels with the source pixels.
+ *   Clear: set pixels to 0
+ *   And: source AND destination
+ *   And Reverse: source AND (NOT destination)
+ *   And Invert: (NOT source) AND destination
+ *   Noop: destination
+ *   Or: source OR destination
+ *   Nor: (NOT source) AND (NOT destination)
+ *   Equiv: (NOT source) XOR destination
+ *   Xor Reverse: source OR (NOT destination)
+ *   Copy Inverted: NOT source
+ *   Xor Inverted: (NOT source) OR destination
+ *   Nand: (NOT source) OR (NOT destination)
+ *   Set: set pixels to 1
+ */
+typedef enum
+{
+  GDK_COPY,
+  GDK_INVERT,
+  GDK_XOR,
+  GDK_CLEAR,
+  GDK_AND,
+  GDK_AND_REVERSE,
+  GDK_AND_INVERT,
+  GDK_NOOP,
+  GDK_OR,
+  GDK_EQUIV,
+  GDK_OR_REVERSE,
+  GDK_COPY_INVERT,
+  GDK_OR_INVERT,
+  GDK_NAND,
+  GDK_SET
+} GdkFunction;
+
+/* GC fill types.
+ *  Solid:
+ *  Tiled:
+ *  Stippled:
+ *  OpaqueStippled:
+ */
+typedef enum
+{
+  GDK_SOLID,
+  GDK_TILED,
+  GDK_STIPPLED,
+  GDK_OPAQUE_STIPPLED
+} GdkFill;
+
+/* GC fill rule for polygons
+ *  EvenOddRule
+ *  WindingRule
+ */
+typedef enum
+{
+  GDK_EVEN_ODD_RULE,
+  GDK_WINDING_RULE
+} GdkFillRule;
+
+/* GC line styles
+ *  Solid:
+ *  OnOffDash:
+ *  DoubleDash:
+ */
+typedef enum
+{
+  GDK_LINE_SOLID,
+  GDK_LINE_ON_OFF_DASH,
+  GDK_LINE_DOUBLE_DASH
+} GdkLineStyle;
+
+/* GC cap styles
+ *  CapNotLast:
+ *  CapButt:
+ *  CapRound:
+ *  CapProjecting:
+ */
+typedef enum
+{
+  GDK_CAP_NOT_LAST,
+  GDK_CAP_BUTT,
+  GDK_CAP_ROUND,
+  GDK_CAP_PROJECTING
+} GdkCapStyle;
+
+/* GC join styles
+ *  JoinMiter:
+ *  JoinRound:
+ *  JoinBevel:
+ */
+typedef enum
+{
+  GDK_JOIN_MITER,
+  GDK_JOIN_ROUND,
+  GDK_JOIN_BEVEL
+} GdkJoinStyle;
+
+/* Cursor types.
+ */
+typedef enum
+{
+#include <gdk/gdkcursors.h>
+  GDK_LAST_CURSOR,
+  GDK_CURSOR_IS_PIXMAP = -1
+} GdkCursorType;
+
+typedef enum {
+  GDK_FILTER_CONTINUE,   /* Event not handled, continue processesing */
+  GDK_FILTER_TRANSLATE,          /* Translated event stored */
+  GDK_FILTER_REMOVE      /* Terminate processing, removing event */
+} GdkFilterReturn;
+
+typedef enum {
+  GDK_VISIBILITY_UNOBSCURED,
+  GDK_VISIBILITY_PARTIAL,
+  GDK_VISIBILITY_FULLY_OBSCURED
+} GdkVisibilityState;
+
+/* Event types.
+ *   Nothing: No event occurred.
+ *   Delete: A window delete event was sent by the window manager.
+ *          The specified window should be deleted.
+ *   Destroy: A window has been destroyed.
+ *   Expose: Part of a window has been uncovered.
+ *   NoExpose: Same as expose, but no expose event was generated.
+ *   VisibilityNotify: A window has become fully/partially/not obscured.
+ *   MotionNotify: The mouse has moved.
+ *   ButtonPress: A mouse button was pressed.
+ *   ButtonRelease: A mouse button was release.
+ *   KeyPress: A key was pressed.
+ *   KeyRelease: A key was released.
+ *   EnterNotify: A window was entered.
+ *   LeaveNotify: A window was exited.
+ *   FocusChange: The focus window has changed. (The focus window gets
+ *               keyboard events).
+ *   Resize: A window has been resized.
+ *   Map: A window has been mapped. (It is now visible on the screen).
+ *   Unmap: A window has been unmapped. (It is no longer visible on
+ *         the screen).
+ */
+typedef enum
+{
+  GDK_NOTHING          = -1,
+  GDK_DELETE           = 0,
+  GDK_DESTROY          = 1,
+  GDK_EXPOSE           = 2,
+  GDK_MOTION_NOTIFY    = 3,
+  GDK_BUTTON_PRESS     = 4,
+  GDK_2BUTTON_PRESS    = 5,
+  GDK_3BUTTON_PRESS    = 6,
+  GDK_BUTTON_RELEASE   = 7,
+  GDK_KEY_PRESS                = 8,
+  GDK_KEY_RELEASE      = 9,
+  GDK_ENTER_NOTIFY     = 10,
+  GDK_LEAVE_NOTIFY     = 11,
+  GDK_FOCUS_CHANGE     = 12,
+  GDK_CONFIGURE                = 13,
+  GDK_MAP              = 14,
+  GDK_UNMAP            = 15,
+  GDK_PROPERTY_NOTIFY  = 16,
+  GDK_SELECTION_CLEAR  = 17,
+  GDK_SELECTION_REQUEST = 18,
+  GDK_SELECTION_NOTIFY = 19,
+  GDK_PROXIMITY_IN     = 20,
+  GDK_PROXIMITY_OUT    = 21,
+  GDK_DRAG_ENTER        = 22,
+  GDK_DRAG_LEAVE        = 23,
+  GDK_DRAG_MOTION       = 24,
+  GDK_DRAG_STATUS       = 25,
+  GDK_DROP_START        = 26,
+  GDK_DROP_FINISHED     = 27,
+  GDK_CLIENT_EVENT     = 28,
+  GDK_VISIBILITY_NOTIFY = 29,
+  GDK_NO_EXPOSE                = 30
+} GdkEventType;
+
+/* Event masks. (Used to select what types of events a window
+ *  will receive).
+ */
+typedef enum
+{
+  GDK_EXPOSURE_MASK            = 1 << 1,
+  GDK_POINTER_MOTION_MASK      = 1 << 2,
+  GDK_POINTER_MOTION_HINT_MASK = 1 << 3,
+  GDK_BUTTON_MOTION_MASK       = 1 << 4,
+  GDK_BUTTON1_MOTION_MASK      = 1 << 5,
+  GDK_BUTTON2_MOTION_MASK      = 1 << 6,
+  GDK_BUTTON3_MOTION_MASK      = 1 << 7,
+  GDK_BUTTON_PRESS_MASK                = 1 << 8,
+  GDK_BUTTON_RELEASE_MASK      = 1 << 9,
+  GDK_KEY_PRESS_MASK           = 1 << 10,
+  GDK_KEY_RELEASE_MASK         = 1 << 11,
+  GDK_ENTER_NOTIFY_MASK                = 1 << 12,
+  GDK_LEAVE_NOTIFY_MASK                = 1 << 13,
+  GDK_FOCUS_CHANGE_MASK                = 1 << 14,
+  GDK_STRUCTURE_MASK           = 1 << 15,
+  GDK_PROPERTY_CHANGE_MASK     = 1 << 16,
+  GDK_VISIBILITY_NOTIFY_MASK   = 1 << 17,
+  GDK_PROXIMITY_IN_MASK                = 1 << 18,
+  GDK_PROXIMITY_OUT_MASK       = 1 << 19,
+  GDK_SUBSTRUCTURE_MASK                = 1 << 20,
+  GDK_ALL_EVENTS_MASK          = 0x0FFFFF
+} GdkEventMask;
+
+/* Types of enter/leave notifications.
+ *   Ancestor:
+ *   Virtual:
+ *   Inferior:
+ *   Nonlinear:
+ *   NonlinearVirtual:
+ *   Unknown: An unknown type of enter/leave event occurred.
+ */
+typedef enum
+{
+  GDK_NOTIFY_ANCESTOR          = 0,
+  GDK_NOTIFY_VIRTUAL           = 1,
+  GDK_NOTIFY_INFERIOR          = 2,
+  GDK_NOTIFY_NONLINEAR         = 3,
+  GDK_NOTIFY_NONLINEAR_VIRTUAL = 4,
+  GDK_NOTIFY_UNKNOWN           = 5
+} GdkNotifyType;
+
+/* Enter/leave event modes.
+ *   NotifyNormal
+ *   NotifyGrab
+ *   NotifyUngrab
+ */
+typedef enum
+{
+  GDK_CROSSING_NORMAL,
+  GDK_CROSSING_GRAB,
+  GDK_CROSSING_UNGRAB
+} GdkCrossingMode;
+
+/* Types of modifiers.
+ */
+typedef enum
+{
+  GDK_SHIFT_MASK    = 1 << 0,
+  GDK_LOCK_MASK            = 1 << 1,
+  GDK_CONTROL_MASK  = 1 << 2,
+  GDK_MOD1_MASK            = 1 << 3,
+  GDK_MOD2_MASK            = 1 << 4,
+  GDK_MOD3_MASK            = 1 << 5,
+  GDK_MOD4_MASK            = 1 << 6,
+  GDK_MOD5_MASK            = 1 << 7,
+  GDK_BUTTON1_MASK  = 1 << 8,
+  GDK_BUTTON2_MASK  = 1 << 9,
+  GDK_BUTTON3_MASK  = 1 << 10,
+  GDK_BUTTON4_MASK  = 1 << 11,
+  GDK_BUTTON5_MASK  = 1 << 12,
+  GDK_RELEASE_MASK  = 1 << 13,
+  GDK_MODIFIER_MASK = 0x3fff
+} GdkModifierType;
+
+typedef enum
+{
+  GDK_CLIP_BY_CHILDREN = 0,
+  GDK_INCLUDE_INFERIORS = 1
+} GdkSubwindowMode;
+
+typedef enum
+{
+  GDK_INPUT_READ       = 1 << 0,
+  GDK_INPUT_WRITE      = 1 << 1,
+  GDK_INPUT_EXCEPTION  = 1 << 2
+} GdkInputCondition;
+
+typedef enum
+{
+  GDK_OK         = 0,
+  GDK_ERROR      = -1,
+  GDK_ERROR_PARAM = -2,
+  GDK_ERROR_FILE  = -3,
+  GDK_ERROR_MEM          = -4
+} GdkStatus;
+
+typedef enum
+{
+  GDK_LSB_FIRST,
+  GDK_MSB_FIRST
+} GdkByteOrder;
+
+typedef enum
+{
+  GDK_GC_FOREGROUND    = 1 << 0,
+  GDK_GC_BACKGROUND    = 1 << 1,
+  GDK_GC_FONT         = 1 << 2,
+  GDK_GC_FUNCTION      = 1 << 3,
+  GDK_GC_FILL         = 1 << 4,
+  GDK_GC_TILE         = 1 << 5,
+  GDK_GC_STIPPLE       = 1 << 6,
+  GDK_GC_CLIP_MASK     = 1 << 7,
+  GDK_GC_SUBWINDOW     = 1 << 8,
+  GDK_GC_TS_X_ORIGIN   = 1 << 9,
+  GDK_GC_TS_Y_ORIGIN   = 1 << 10,
+  GDK_GC_CLIP_X_ORIGIN = 1 << 11,
+  GDK_GC_CLIP_Y_ORIGIN = 1 << 12,
+  GDK_GC_EXPOSURES     = 1 << 13,
+  GDK_GC_LINE_WIDTH    = 1 << 14,
+  GDK_GC_LINE_STYLE    = 1 << 15,
+  GDK_GC_CAP_STYLE     = 1 << 16,
+  GDK_GC_JOIN_STYLE    = 1 << 17
+} GdkGCValuesMask;
+
+typedef enum
+{
+  GDK_SELECTION_PRIMARY = 1,
+  GDK_SELECTION_SECONDARY = 2
+} GdkSelection;
+
+typedef enum
+{
+  GDK_PROPERTY_NEW_VALUE,
+  GDK_PROPERTY_DELETE
+} GdkPropertyState;
+
+typedef enum
+{
+  GDK_PROP_MODE_REPLACE,
+  GDK_PROP_MODE_PREPEND,
+  GDK_PROP_MODE_APPEND
+} GdkPropMode;
+
+/* Enums for XInput support */
+
+typedef enum
+{
+  GDK_SOURCE_MOUSE,
+  GDK_SOURCE_PEN,
+  GDK_SOURCE_ERASER,
+  GDK_SOURCE_CURSOR
+} GdkInputSource;
+
+typedef enum
+{
+  GDK_MODE_DISABLED,
+  GDK_MODE_SCREEN,
+  GDK_MODE_WINDOW
+} GdkInputMode;
+
+typedef enum
+{
+  GDK_AXIS_IGNORE,
+  GDK_AXIS_X,
+  GDK_AXIS_Y,
+  GDK_AXIS_PRESSURE,
+  GDK_AXIS_XTILT,
+  GDK_AXIS_YTILT,
+  GDK_AXIS_LAST
+} GdkAxisUse;
+
+/* The next two types define enums for predefined atoms relating
+   to selections. In general, one will need to use gdk_intern_atom */
+
+typedef enum
+{
+  GDK_TARGET_BITMAP = 5,
+  GDK_TARGET_COLORMAP = 7,
+  GDK_TARGET_DRAWABLE = 17,
+  GDK_TARGET_PIXMAP = 20,
+  GDK_TARGET_STRING = 31
+} GdkTarget;
+
+typedef enum
+{
+  GDK_SELECTION_TYPE_ATOM = 4,
+  GDK_SELECTION_TYPE_BITMAP = 5,
+  GDK_SELECTION_TYPE_COLORMAP = 7,
+  GDK_SELECTION_TYPE_DRAWABLE = 17,
+  GDK_SELECTION_TYPE_INTEGER = 19,
+  GDK_SELECTION_TYPE_PIXMAP = 20,
+  GDK_SELECTION_TYPE_WINDOW = 33,
+  GDK_SELECTION_TYPE_STRING = 31
+} GdkSelectionType;
+
+typedef enum
+{
+  GDK_EXTENSION_EVENTS_NONE,
+  GDK_EXTENSION_EVENTS_ALL,
+  GDK_EXTENSION_EVENTS_CURSOR
+} GdkExtensionMode;
+
+typedef enum                   /*< flags >*/
+{
+  GDK_IM_PREEDIT_AREA     = 0x0001, 
+  GDK_IM_PREEDIT_CALLBACKS = 0x0002, 
+  GDK_IM_PREEDIT_POSITION  = 0x0004,
+  GDK_IM_PREEDIT_NOTHING   = 0x0008,
+  GDK_IM_PREEDIT_NONE     = 0x0010,
+  GDK_IM_PREEDIT_MASK      = 0x001f,
+
+  GDK_IM_STATUS_AREA      = 0x0100, 
+  GDK_IM_STATUS_CALLBACKS  = 0x0200,
+  GDK_IM_STATUS_NOTHING           = 0x0400,
+  GDK_IM_STATUS_NONE      = 0x0800,
+  GDK_IM_STATUS_MASK      = 0x0f00 
+} GdkIMStyle;
+
+typedef enum
+{
+  GDK_IC_STYLE                 = 1 << 0,
+  GDK_IC_CLIENT_WINDOW         = 1 << 1,
+  GDK_IC_FOCUS_WINDOW          = 1 << 2,
+  GDK_IC_FILTER_EVENTS         = 1 << 3,
+  GDK_IC_SPOT_LOCATION         = 1 << 4,
+  GDK_IC_LINE_SPACING          = 1 << 5,
+  GDK_IC_CURSOR                        = 1 << 6,
+
+  GDK_IC_PREEDIT_FONTSET       = 1 << 10,
+  GDK_IC_PREEDIT_AREA          = 1 << 11,
+  GDK_IC_PREEDIT_AREA_NEEDED   = 1 << 12,
+  GDK_IC_PREEDIT_FOREGROUND    = 1 << 13,
+  GDK_IC_PREEDIT_BACKGROUND    = 1 << 14,
+  GDK_IC_PREEDIT_PIXMAP                = 1 << 15,
+  GDK_IC_PREEDIT_COLORMAP      = 1 << 16,
+
+  GDK_IC_STATUS_FONTSET                = 1 << 21,
+  GDK_IC_STATUS_AREA           = 1 << 22,
+  GDK_IC_STATUS_AREA_NEEDED    = 1 << 23,
+  GDK_IC_STATUS_FOREGROUND     = 1 << 24,
+  GDK_IC_STATUS_BACKGROUND     = 1 << 25,
+  GDK_IC_STATUS_PIXMAP         = 1 << 26,
+  GDK_IC_STATUS_COLORMAP       = 1 << 27,
+
+  GDK_IC_ALL_REQ               = GDK_IC_STYLE |
+                                 GDK_IC_CLIENT_WINDOW,
+
+  GDK_IC_PREEDIT_AREA_REQ      = GDK_IC_PREEDIT_AREA | 
+                                 GDK_IC_PREEDIT_FONTSET,
+  GDK_IC_PREEDIT_POSITION_REQ  = GDK_IC_PREEDIT_AREA | GDK_IC_SPOT_LOCATION |
+                                 GDK_IC_PREEDIT_FONTSET,
+
+  GDK_IC_STATUS_AREA_REQ       = GDK_IC_STATUS_AREA | 
+                                 GDK_IC_STATUS_FONTSET
+} GdkICAttributesType;
+
+/* The next two enumeration values current match the
+ * Motif constants. If this is changed, the implementation
+ * of gdk_window_set_decorations/gdk_window_set_functions
+ * will need to change as well.
+ */
+typedef enum
+{
+  GDK_DECOR_ALL                = 1 << 0,
+  GDK_DECOR_BORDER     = 1 << 1,
+  GDK_DECOR_RESIZEH    = 1 << 2,
+  GDK_DECOR_TITLE      = 1 << 3,
+  GDK_DECOR_MENU       = 1 << 4,
+  GDK_DECOR_MINIMIZE   = 1 << 5,
+  GDK_DECOR_MAXIMIZE   = 1 << 6
+} GdkWMDecoration;
+
+typedef enum
+{
+  GDK_FUNC_ALL         = 1 << 0,
+  GDK_FUNC_RESIZE      = 1 << 1,
+  GDK_FUNC_MOVE                = 1 << 2,
+  GDK_FUNC_MINIMIZE    = 1 << 3,
+  GDK_FUNC_MAXIMIZE    = 1 << 4,
+  GDK_FUNC_CLOSE       = 1 << 5
+} GdkWMFunction;
+
+typedef void (*GdkInputFunction) (gpointer         data,
+                                 gint              source,
+                                 GdkInputCondition condition);
+
+typedef void (*GdkDestroyNotify) (gpointer data);
+
+/* Color Context modes.
+ *
+ * GDK_CC_MODE_UNDEFINED - unknown
+ * GDK_CC_MODE_BW       - default B/W
+ * GDK_CC_MODE_STD_CMAP         - has a standard colormap
+ * GDK_CC_MODE_TRUE     - is a TrueColor/DirectColor visual
+ * GDK_CC_MODE_MY_GRAY  - my grayramp
+ * GDK_CC_MODE_PALETTE  - has a pre-allocated palette
+ */ 
+
+typedef enum
+{
+  GDK_CC_MODE_UNDEFINED,
+  GDK_CC_MODE_BW,
+  GDK_CC_MODE_STD_CMAP,
+  GDK_CC_MODE_TRUE,
+  GDK_CC_MODE_MY_GRAY,
+  GDK_CC_MODE_PALETTE
+} GdkColorContextMode;
+
+/* Types of overlapping between a rectangle and a region
+ * GDK_OVERLAP_RECTANGLE_IN: rectangle is in region
+ * GDK_OVERLAP_RECTANGLE_OUT: rectangle in not in region
+ * GDK_OVERLAP_RECTANGLE_PART: rectangle in partially in region
+ */
+
+typedef enum
+{
+  GDK_OVERLAP_RECTANGLE_IN,
+  GDK_OVERLAP_RECTANGLE_OUT,
+  GDK_OVERLAP_RECTANGLE_PART
+} GdkOverlapType;
+
+typedef enum {
+  GDK_ACTION_DEFAULT = 1 << 0,
+  GDK_ACTION_COPY    = 1 << 1,
+  GDK_ACTION_MOVE    = 1 << 2,
+  GDK_ACTION_LINK    = 1 << 3,
+  GDK_ACTION_PRIVATE = 1 << 4,
+  GDK_ACTION_ASK     = 1 << 5
+} GdkDragAction;
+
+typedef enum {
+  GDK_DRAG_PROTO_MOTIF,
+  GDK_DRAG_PROTO_XDND,
+  GDK_DRAG_PROTO_ROOTWIN,      /* A root window with nobody claiming drags */
+  GDK_DRAG_PROTO_WIN32_DROPFILES, /* The simple WM_DROPFILES dnd */
+  GDK_DRAG_PROTO_OLE2,         /* The complex OLE2 dnd */
+  GDK_DRAG_PROTO_NONE          /* Not a valid drag window */
+} GdkDragProtocol;
+
+/* The color type.
+ *   A color consists of red, green and blue values in the
+ *    range 0-65535 and a pixel value. The pixel value is highly
+ *    dependent on the depth and colormap which this color will
+ *    be used to draw into. Therefore, sharing colors between
+ *    colormaps is a bad idea.
+ */
+struct _GdkColor
+{
+  gulong  pixel;
+  gushort red;
+  gushort green;
+  gushort blue;
+};
+
+/* The colormap type.
+ *   Colormaps consist of 256 colors.
+ */
+struct _GdkColormap
+{
+  gint      size;
+  GdkColor *colors;
+};
+
+/* The visual type.
+ *   "type" is the type of visual this is (PseudoColor, TrueColor, etc).
+ *   "depth" is the bit depth of this visual.
+ *   "colormap_size" is the size of a colormap for this visual.
+ *   "bits_per_rgb" is the number of significant bits per red, green and blue.
+ *  The red, green and blue masks, shifts and precisions refer
+ *   to value needed to calculate pixel values in TrueColor and DirectColor
+ *   visuals. The "mask" is the significant bits within the pixel. The
+ *   "shift" is the number of bits left we must shift a primary for it
+ *   to be in position (according to the "mask"). "prec" refers to how
+ *   much precision the pixel value contains for a particular primary.
+ */
+struct _GdkVisual
+{
+  GdkVisualType type;
+  gint depth;
+  GdkByteOrder byte_order;
+  gint colormap_size;
+  gint bits_per_rgb;
+
+  guint32 red_mask;
+  gint red_shift;
+  gint red_prec;
+
+  guint32 green_mask;
+  gint green_shift;
+  gint green_prec;
+
+  guint32 blue_mask;
+  gint blue_shift;
+  gint blue_prec;
+};
+
+struct _GdkWindowAttr
+{
+  gchar *title;
+  gint event_mask;
+  gint16 x, y;
+  gint16 width;
+  gint16 height;
+  GdkWindowClass wclass;
+  GdkVisual *visual;
+  GdkColormap *colormap;
+  GdkWindowType window_type;
+  GdkCursor *cursor;
+  gchar *wmclass_name;
+  gchar *wmclass_class;
+  gboolean override_redirect;
+};
+
+struct _GdkWindow
+{
+  gpointer user_data;
+};
+
+struct _GdkGeometry {
+  gint min_width;
+  gint min_height;
+  gint max_width;
+  gint max_height;
+  gint base_width;
+  gint base_height;
+  gint width_inc;
+  gint height_inc;
+  gdouble min_aspect;
+  gdouble max_aspect;
+  /* GdkGravity gravity; */
+};
+
+struct _GdkImage
+{
+  GdkImageType type;
+  GdkVisual    *visual;            /* visual used to create the image */
+  GdkByteOrder byte_order;
+  guint16      width;
+  guint16      height;
+  guint16      depth;
+  guint16      bpp;        /* bytes per pixel */
+  guint16      bpl;        /* bytes per line */
+  gpointer     mem;
+};
+
+struct _GdkGCValues
+{
+  GdkColor         foreground;
+  GdkColor         background;
+  GdkFont         *font;
+  GdkFunction      function;
+  GdkFill          fill;
+  GdkPixmap       *tile;
+  GdkPixmap       *stipple;
+  GdkPixmap       *clip_mask;
+  GdkSubwindowMode  subwindow_mode;
+  gint             ts_x_origin;
+  gint             ts_y_origin;
+  gint             clip_x_origin;
+  gint             clip_y_origin;
+  gint             graphics_exposures;
+  gint             line_width;
+  GdkLineStyle     line_style;
+  GdkCapStyle      cap_style;
+  GdkJoinStyle     join_style;
+};
+
+struct _GdkGC
+{
+  gint dummy_var;
+};
+
+struct _GdkPoint
+{
+  gint16 x;
+  gint16 y;
+};
+
+struct _GdkRectangle
+{
+  gint16 x;
+  gint16 y;
+  guint16 width;
+  guint16 height;
+};
+
+struct _GdkSegment
+{
+  gint16 x1;
+  gint16 y1;
+  gint16 x2;
+  gint16 y2;
+};
+
+struct _GdkFont
+{
+  GdkFontType type;
+  gint ascent;
+  gint descent;
+};
+
+struct _GdkCursor
+{
+  GdkCursorType type;
+};
+
+
+struct _GdkColorContextDither
+{
+  gint fast_rgb[32][32][32]; /* quick look-up table for faster rendering */
+  gint fast_err[32][32][32]; /* internal RGB error information */
+  gint fast_erg[32][32][32];
+  gint fast_erb[32][32][32];
+};
+
+struct _GdkColorContext
+{
+  GdkVisual *visual;
+  GdkColormap *colormap;
+
+  gint num_colors;             /* available no. of colors in colormap */
+  gint max_colors;             /* maximum no. of colors */
+  gint num_allocated;          /* no. of allocated colors */
+
+  GdkColorContextMode mode;
+  gint need_to_free_colormap;
+  GdkAtom std_cmap_atom;
+
+  gulong *clut;                        /* color look-up table */
+  GdkColor *cmap;              /* colormap */
+
+  GHashTable *color_hash;      /* hash table of allocated colors */
+  GdkColor *palette;           /* preallocated palette */
+  gint num_palette;            /* size of palette */
+
+  GdkColorContextDither *fast_dither;  /* fast dither matrix */
+
+  struct
+  {
+    gint red;
+    gint green;
+    gint blue;
+  } shifts;
+
+  struct
+  {
+    gulong red;
+    gulong green;
+    gulong blue;
+  } masks;
+
+  struct
+  {
+    gint red;
+    gint green;
+    gint blue;
+  } bits;
+
+  gulong max_entry;
+
+  gulong black_pixel;
+  gulong white_pixel;
+};
+
+/* Types for XInput support */
+
+struct _GdkDeviceKey
+{
+  guint keyval;
+  GdkModifierType modifiers;
+};
+
+struct _GdkDeviceInfo
+{
+  guint32 deviceid;
+  gchar *name;
+  GdkInputSource source;
+  GdkInputMode mode;
+  gint has_cursor;     /* TRUE if the X pointer follows device motion */
+  gint num_axes;
+  GdkAxisUse *axes;    /* Specifies use for each axis */
+  gint num_keys;
+  GdkDeviceKey *keys;
+};
+
+struct _GdkTimeCoord
+{
+  guint32 time;
+  gdouble x;
+  gdouble y;
+  gdouble pressure;
+  gdouble xtilt;
+  gdouble ytilt;
+};
+
+/* Structure that holds information about a drag in progress.
+ * this is used on both source and destination sides.
+ */
+struct _GdkDragContext {
+  GdkDragProtocol protocol;
+  
+  gboolean is_source;
+  
+  GdkWindow *source_window;
+  GdkWindow *dest_window;
+
+  GList *targets;
+  GdkDragAction actions;
+  GdkDragAction suggested_action;
+  GdkDragAction action; 
+
+  guint32 start_time;
+};
+
+/* Event filtering */
+
+typedef void GdkXEvent;          /* Can be cast to XEvent */
+
+typedef GdkFilterReturn (*GdkFilterFunc) (GdkXEvent *xevent,
+                                         GdkEvent *event,
+                                         gpointer  data);
+
+struct _GdkEventAny
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+};
+
+struct _GdkEventExpose
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkRectangle area;
+  gint count; /* If non-zero, how many more events follow. */
+};
+
+struct _GdkEventNoExpose
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  /* XXX: does anyone need the X major_code or minor_code fields? */
+};
+
+struct _GdkEventVisibility
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkVisibilityState state;
+};
+
+struct _GdkEventMotion
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  guint32 time;
+  gdouble x;
+  gdouble y;
+  gdouble pressure;
+  gdouble xtilt;
+  gdouble ytilt;
+  guint state;
+  gint16 is_hint;
+  GdkInputSource source;
+  guint32 deviceid;
+  gdouble x_root, y_root;
+};
+
+struct _GdkEventButton
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  guint32 time;
+  gdouble x;
+  gdouble y;
+  gdouble pressure;
+  gdouble xtilt;
+  gdouble ytilt;
+  guint state;
+  guint button;
+  GdkInputSource source;
+  guint32 deviceid;
+  gdouble x_root, y_root;
+};
+
+struct _GdkEventKey
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  guint32 time;
+  guint state;
+  guint keyval;
+  gint length;
+  gchar *string;
+};
+
+struct _GdkEventCrossing
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkWindow *subwindow;
+  guint32 time;
+  gdouble x;
+  gdouble y;
+  gdouble x_root;
+  gdouble y_root;
+  GdkCrossingMode mode;
+  GdkNotifyType detail;
+  gboolean focus;
+  guint state;
+};
+
+struct _GdkEventFocus
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  gint16 in;
+};
+
+struct _GdkEventConfigure
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  gint16 x, y;
+  gint16 width;
+  gint16 height;
+};
+
+struct _GdkEventProperty
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkAtom atom;
+  guint32 time;
+  guint state;
+};
+
+struct _GdkEventSelection
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkAtom selection;
+  GdkAtom target;
+  GdkAtom property;
+  guint32 requestor;
+  guint32 time;
+};
+
+/* This event type will be used pretty rarely. It only is important
+   for XInput aware programs that are drawing their own cursor */
+
+struct _GdkEventProximity
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  guint32 time;
+  GdkInputSource source;
+  guint32 deviceid;
+};
+
+struct _GdkEventClient
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkAtom message_type;
+  gushort data_format;
+  union {
+    char b[20];
+    short s[10];
+    long l[5];
+  } data;
+};
+
+/* Event types for DND */
+
+struct _GdkEventDND {
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkDragContext *context;
+
+  guint32 time;
+  gshort x_root, y_root;
+};
+
+union _GdkEvent
+{
+  GdkEventType             type;
+  GdkEventAny              any;
+  GdkEventExpose           expose;
+  GdkEventNoExpose         no_expose;
+  GdkEventVisibility       visibility;
+  GdkEventMotion           motion;
+  GdkEventButton           button;
+  GdkEventKey              key;
+  GdkEventCrossing         crossing;
+  GdkEventFocus                    focus_change;
+  GdkEventConfigure        configure;
+  GdkEventProperty         property;
+  GdkEventSelection        selection;
+  GdkEventProximity        proximity;
+  GdkEventClient           client;
+  GdkEventDND               dnd;
+};
+
+struct _GdkRegion
+{
+  gpointer user_data;
+};
+
+struct _GdkICAttr
+{
+  GdkIMStyle style;
+  GdkWindow *client_window;
+  GdkWindow *focus_window;
+  GdkEventMask filter_events;
+  GdkPoint spot_location;
+  gint line_spacing;
+  GdkCursor *cursor;
+
+  GdkFont *preedit_fontset;
+  GdkRectangle preedit_area;
+  GdkRectangle preedit_area_needed; 
+  GdkColor preedit_foreground;
+  GdkColor preedit_background;
+  GdkPixmap *preedit_pixmap;
+  GdkColormap *preedit_colormap;
+
+  GdkFont *status_fontset;
+  GdkRectangle status_area;
+  GdkRectangle status_area_needed; 
+  GdkColor status_foreground;
+  GdkColor status_background;
+  GdkPixmap *status_pixmap;
+  GdkColormap *status_colormap;
+};
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GDK_TYPES_H__ */
diff --git a/gdk/win32/gdkvisual-win32.c b/gdk/win32/gdkvisual-win32.c
new file mode 100644 (file)
index 0000000..e207fde
--- /dev/null
@@ -0,0 +1,527 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkx.h"
+
+static void  gdk_visual_add            (GdkVisual *visual);
+static void  gdk_visual_decompose_mask (gulong     mask,
+                                       gint      *shift,
+                                       gint      *prec);
+static guint gdk_visual_hash           (Visual    *key);
+static gint  gdk_visual_compare        (Visual    *a,
+                                       Visual    *b);
+
+
+static GdkVisualPrivate *system_visual;
+static GdkVisualPrivate *visuals;
+static gint nvisuals;
+
+static gint available_depths[7];
+static gint navailable_depths;
+
+static GdkVisualType available_types[6];
+static gint navailable_types;
+
+#ifdef G_ENABLE_DEBUG
+
+static const gchar* visual_names[] =
+{
+  "static gray",
+  "grayscale",
+  "static color",
+  "pseudo color",
+  "true color",
+  "direct color",
+};
+
+#endif /* G_ENABLE_DEBUG */
+
+static GHashTable *visual_hash = NULL;
+
+void
+gdk_visual_init (void)
+{
+  struct
+  {
+    BITMAPINFOHEADER bi;
+    union
+    {
+      RGBQUAD colors[256];
+      DWORD fields[256];
+    } u;
+  } bmi;
+  HBITMAP hbm;
+
+  static const gint possible_depths[7] = { 32, 24, 16, 15, 8, 4, 1 };
+  static const GdkVisualType possible_types[6] =
+    {
+      GDK_VISUAL_DIRECT_COLOR,
+      GDK_VISUAL_TRUE_COLOR,
+      GDK_VISUAL_PSEUDO_COLOR,
+      GDK_VISUAL_STATIC_COLOR,
+      GDK_VISUAL_GRAYSCALE,
+      GDK_VISUAL_STATIC_GRAY
+    };
+
+  static const gint npossible_depths = sizeof(possible_depths)/sizeof(gint);
+  static const gint npossible_types = sizeof(possible_types)/sizeof(GdkVisualType);
+
+  int rastercaps, numcolors, sizepalette, colorres, bitspixel;
+  Visual *default_xvisual;
+  GdkVisualPrivate temp_visual;
+  int nxvisuals;
+  int i, j;
+
+  nxvisuals = 1;
+  visuals = g_new (GdkVisualPrivate, nxvisuals);
+
+  nvisuals = 0;
+  for (i = 0; i < nxvisuals; i++)
+    {
+      if (1)
+       {
+         bitspixel = GetDeviceCaps (gdk_DC, BITSPIXEL);
+         rastercaps = GetDeviceCaps (gdk_DC, RASTERCAPS);
+         default_xvisual = g_new (Visual, 1);
+         visuals[nvisuals].xvisual = default_xvisual;
+         visuals[nvisuals].xvisual->visualid = nvisuals;
+         visuals[nvisuals].xvisual->bitspixel = bitspixel;
+
+         if (rastercaps & RC_PALETTE)
+           {
+             visuals[nvisuals].visual.type = GDK_VISUAL_PSEUDO_COLOR;
+             numcolors = GetDeviceCaps (gdk_DC, NUMCOLORS);
+             sizepalette = GetDeviceCaps (gdk_DC, SIZEPALETTE);
+             colorres = GetDeviceCaps (gdk_DC, COLORRES);
+             visuals[nvisuals].xvisual->map_entries = sizepalette;
+           }
+         else if (bitspixel == 1)
+           {
+             visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_GRAY;
+             visuals[nvisuals].xvisual->map_entries = 2;
+           }
+         else if (bitspixel == 4)
+           {
+             visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR;
+             visuals[nvisuals].xvisual->map_entries = 16;
+           }
+         else if (bitspixel == 8)
+           {
+             visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR;
+             visuals[nvisuals].xvisual->map_entries = 256;
+           }
+         else if (bitspixel == 16)
+           {
+             visuals[nvisuals].visual.type = GDK_VISUAL_TRUE_COLOR;
+#if 1
+             /* This code by Mike Enright,
+              * see http://www.users.cts.com/sd/m/menright/display.html
+              */
+             memset (&bmi, 0, sizeof (bmi));
+             bmi.bi.biSize = sizeof (bmi.bi);
+  
+             hbm = CreateCompatibleBitmap (gdk_DC, 1, 1);
+             GetDIBits (gdk_DC, hbm, 0, 1, NULL,
+                        (BITMAPINFO *) &bmi, DIB_RGB_COLORS);
+             GetDIBits (gdk_DC, hbm, 0, 1, NULL,
+                        (BITMAPINFO *) &bmi, DIB_RGB_COLORS);
+             DeleteObject (hbm);
+
+             if (bmi.bi.biCompression != BI_BITFIELDS)
+               {
+                 /* Either BI_RGB or BI_RLE_something
+                  * .... or perhaps (!!) something else.
+                  * Theoretically biCompression might be
+                  * mmioFourCC('c','v','i','d') but I doubt it.
+                  */
+                 if (bmi.bi.biCompression == BI_RGB)
+                   {
+                     /* It's 555 */
+                     bitspixel = 15;
+                     visuals[nvisuals].visual.red_mask   = 0x00007C00;
+                     visuals[nvisuals].visual.green_mask = 0x000003E0;
+                     visuals[nvisuals].visual.blue_mask  = 0x0000001F;
+                   }
+                 else
+                   {
+                     g_assert_not_reached ();
+                   }
+               }
+             else
+               {
+                 DWORD allmasks =
+                   bmi.u.fields[0] | bmi.u.fields[1] | bmi.u.fields[2];
+                 int k = 0;
+                 while (allmasks)
+                   {
+                     if (allmasks&1)
+                       k++;
+                     allmasks/=2;
+                   }
+                 bitspixel = k;
+                 visuals[nvisuals].visual.red_mask = bmi.u.fields[0];
+                 visuals[nvisuals].visual.green_mask = bmi.u.fields[1];
+                 visuals[nvisuals].visual.blue_mask  = bmi.u.fields[2];
+               }
+#else
+             /* Old, incorrect (but still working) code. */
+#if 0
+             visuals[nvisuals].visual.red_mask   = 0x0000F800;
+             visuals[nvisuals].visual.green_mask = 0x000007E0;
+             visuals[nvisuals].visual.blue_mask  = 0x0000001F;
+#else
+             visuals[nvisuals].visual.red_mask   = 0x00007C00;
+             visuals[nvisuals].visual.green_mask = 0x000003E0;
+             visuals[nvisuals].visual.blue_mask  = 0x0000001F;
+#endif
+#endif
+           }
+         else if (bitspixel == 24 || bitspixel == 32)
+           {
+             visuals[nvisuals].visual.type = GDK_VISUAL_TRUE_COLOR;
+             visuals[nvisuals].visual.red_mask   = 0x00FF0000;
+             visuals[nvisuals].visual.green_mask = 0x0000FF00;
+             visuals[nvisuals].visual.blue_mask  = 0x000000FF;
+           }
+         else
+           g_error ("gdk_visual_init: unsupported BITSPIXEL: %d\n", bitspixel);
+
+         visuals[nvisuals].visual.depth = bitspixel;
+         visuals[nvisuals].visual.byte_order = GDK_LSB_FIRST;
+         visuals[nvisuals].visual.bits_per_rgb = 42; /* Not used? */
+
+         if ((visuals[nvisuals].visual.type == GDK_VISUAL_TRUE_COLOR) ||
+             (visuals[nvisuals].visual.type == GDK_VISUAL_DIRECT_COLOR))
+           {
+             gdk_visual_decompose_mask (visuals[nvisuals].visual.red_mask,
+                                        &visuals[nvisuals].visual.red_shift,
+                                        &visuals[nvisuals].visual.red_prec);
+
+             gdk_visual_decompose_mask (visuals[nvisuals].visual.green_mask,
+                                        &visuals[nvisuals].visual.green_shift,
+                                        &visuals[nvisuals].visual.green_prec);
+
+             gdk_visual_decompose_mask (visuals[nvisuals].visual.blue_mask,
+                                        &visuals[nvisuals].visual.blue_shift,
+                                        &visuals[nvisuals].visual.blue_prec);
+             visuals[nvisuals].xvisual->map_entries =
+               1 << (MAX (visuals[nvisuals].visual.red_prec,
+                          MAX (visuals[nvisuals].visual.green_prec,
+                               visuals[nvisuals].visual.blue_prec)));
+           }
+         else
+           {
+             visuals[nvisuals].visual.red_mask = 0;
+             visuals[nvisuals].visual.red_shift = 0;
+             visuals[nvisuals].visual.red_prec = 0;
+
+             visuals[nvisuals].visual.green_mask = 0;
+             visuals[nvisuals].visual.green_shift = 0;
+             visuals[nvisuals].visual.green_prec = 0;
+
+             visuals[nvisuals].visual.blue_mask = 0;
+             visuals[nvisuals].visual.blue_shift = 0;
+             visuals[nvisuals].visual.blue_prec = 0;
+           }
+         visuals[nvisuals].visual.colormap_size = visuals[nvisuals].xvisual->map_entries;
+
+         nvisuals += 1;
+       }
+    }
+
+  for (i = 0; i < nvisuals; i++)
+    {
+      for (j = i+1; j < nvisuals; j++)
+       {
+         if (visuals[j].visual.depth >= visuals[i].visual.depth)
+           {
+             if ((visuals[j].visual.depth == 8) && (visuals[i].visual.depth == 8))
+               {
+                 if (visuals[j].visual.type == GDK_VISUAL_PSEUDO_COLOR)
+                   {
+                     temp_visual = visuals[j];
+                     visuals[j] = visuals[i];
+                     visuals[i] = temp_visual;
+                   }
+                 else if ((visuals[i].visual.type != GDK_VISUAL_PSEUDO_COLOR) &&
+                          visuals[j].visual.type > visuals[i].visual.type)
+                   {
+                     temp_visual = visuals[j];
+                     visuals[j] = visuals[i];
+                     visuals[i] = temp_visual;
+                   }
+               }
+             else if ((visuals[j].visual.depth > visuals[i].visual.depth) ||
+                      ((visuals[j].visual.depth == visuals[i].visual.depth) &&
+                       (visuals[j].visual.type > visuals[i].visual.type)))
+               {
+                 temp_visual = visuals[j];
+                 visuals[j] = visuals[i];
+                 visuals[i] = temp_visual;
+               }
+           }
+       }
+    }
+
+  for (i = 0; i < nvisuals; i++)
+    if (default_xvisual->visualid == visuals[i].xvisual->visualid)
+      {
+       system_visual = &visuals[i];
+       break;
+      }
+
+  navailable_depths = 0;
+  for (i = 0; i < npossible_depths; i++)
+    {
+      for (j = 0; j < nvisuals; j++)
+       {
+         if (visuals[j].visual.depth == possible_depths[i])
+           {
+             available_depths[navailable_depths++] = visuals[j].visual.depth;
+             break;
+           }
+       }
+    }
+
+  if (navailable_depths == 0)
+    g_error ("unable to find a usable depth");
+
+  navailable_types = 0;
+  for (i = 0; i < npossible_types; i++)
+    {
+      for (j = 0; j < nvisuals; j++)
+       {
+         if (visuals[j].visual.type == possible_types[i])
+           {
+             available_types[navailable_types++] = visuals[j].visual.type;
+             break;
+           }
+       }
+    }
+
+  for (i = 0; i < nvisuals; i++)
+    gdk_visual_add ((GdkVisual*) &visuals[i]);
+
+  if (npossible_types == 0)
+    g_error ("unable to find a usable visual type");
+}
+
+GdkVisual*
+gdk_visual_ref (GdkVisual *visual)
+{
+  return visual;
+}
+
+void
+gdk_visual_unref (GdkVisual *visual)
+{
+  return;
+}
+
+gint
+gdk_visual_get_best_depth (void)
+{
+  return available_depths[0];
+}
+
+GdkVisualType
+gdk_visual_get_best_type (void)
+{
+  return available_types[0];
+}
+
+GdkVisual*
+gdk_visual_get_system (void)
+{
+  return ((GdkVisual*) system_visual);
+}
+
+GdkVisual*
+gdk_visual_get_best (void)
+{
+  return ((GdkVisual*) &(visuals[0]));
+}
+
+GdkVisual*
+gdk_visual_get_best_with_depth (gint depth)
+{
+  GdkVisual *return_val;
+  int i;
+
+  return_val = NULL;
+  for (i = 0; i < nvisuals; i++)
+    if (depth == visuals[i].visual.depth)
+      {
+       return_val = (GdkVisual*) &(visuals[i]);
+       break;
+      }
+
+  return return_val;
+}
+
+GdkVisual*
+gdk_visual_get_best_with_type (GdkVisualType visual_type)
+{
+  GdkVisual *return_val;
+  int i;
+
+  return_val = NULL;
+  for (i = 0; i < nvisuals; i++)
+    if (visual_type == visuals[i].visual.type)
+      {
+       return_val = (GdkVisual*) &(visuals[i]);
+       break;
+      }
+
+  return return_val;
+}
+
+GdkVisual*
+gdk_visual_get_best_with_both (gint          depth,
+                              GdkVisualType visual_type)
+{
+  GdkVisual *return_val;
+  int i;
+
+  return_val = NULL;
+  for (i = 0; i < nvisuals; i++)
+    if ((depth == visuals[i].visual.depth) &&
+       (visual_type == visuals[i].visual.type))
+      {
+       return_val = (GdkVisual*) &(visuals[i]);
+       break;
+      }
+
+  return return_val;
+}
+
+void
+gdk_query_depths  (gint **depths,
+                  gint  *count)
+{
+  *count = navailable_depths;
+  *depths = available_depths;
+}
+
+void
+gdk_query_visual_types (GdkVisualType **visual_types,
+                       gint           *count)
+{
+  *count = navailable_types;
+  *visual_types = available_types;
+}
+
+GList*
+gdk_list_visuals (void)
+{
+  GList *list;
+  guint i;
+
+  list = NULL;
+  for (i = 0; i < nvisuals; ++i)
+    list = g_list_append (list, (gpointer) &visuals[i]);
+
+  return list;
+}
+
+GdkVisual*
+gdk_visual_lookup (Visual *xvisual)
+{
+  GdkVisual *visual;
+
+  if (!visual_hash)
+    return NULL;
+
+  visual = g_hash_table_lookup (visual_hash, xvisual);
+  return visual;
+}
+
+GdkVisual*
+gdkx_visual_get (VisualID xvisualid)
+{
+  int i;
+
+  for (i = 0; i < nvisuals; i++)
+    if (xvisualid == visuals[i].xvisual->visualid)
+      return (GdkVisual*) &visuals[i];
+
+  return NULL;
+}
+
+static void
+gdk_visual_add (GdkVisual *visual)
+{
+  GdkVisualPrivate *private;
+
+  if (!visual_hash)
+    visual_hash = g_hash_table_new ((GHashFunc) gdk_visual_hash,
+                                   (GCompareFunc) gdk_visual_compare);
+
+  private = (GdkVisualPrivate*) visual;
+
+  g_hash_table_insert (visual_hash, private->xvisual, visual);
+}
+
+static void
+gdk_visual_decompose_mask (gulong  mask,
+                          gint   *shift,
+                          gint   *prec)
+{
+  *shift = 0;
+  *prec = 0;
+
+  while (!(mask & 0x1))
+    {
+      (*shift)++;
+      mask >>= 1;
+    }
+
+  while (mask & 0x1)
+    {
+      (*prec)++;
+      mask >>= 1;
+    }
+}
+
+/* This hash stuff is pretty useless on Windows, as there is only
+   one visual... */
+
+static guint
+gdk_visual_hash (Visual *key)
+{
+  return key->visualid;
+}
+
+static gint
+gdk_visual_compare (Visual *a,
+                   Visual *b)
+{
+  return (a->visualid == b->visualid);
+}
diff --git a/gdk/win32/gdkvisual.c b/gdk/win32/gdkvisual.c
new file mode 100644 (file)
index 0000000..e207fde
--- /dev/null
@@ -0,0 +1,527 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkx.h"
+
+static void  gdk_visual_add            (GdkVisual *visual);
+static void  gdk_visual_decompose_mask (gulong     mask,
+                                       gint      *shift,
+                                       gint      *prec);
+static guint gdk_visual_hash           (Visual    *key);
+static gint  gdk_visual_compare        (Visual    *a,
+                                       Visual    *b);
+
+
+static GdkVisualPrivate *system_visual;
+static GdkVisualPrivate *visuals;
+static gint nvisuals;
+
+static gint available_depths[7];
+static gint navailable_depths;
+
+static GdkVisualType available_types[6];
+static gint navailable_types;
+
+#ifdef G_ENABLE_DEBUG
+
+static const gchar* visual_names[] =
+{
+  "static gray",
+  "grayscale",
+  "static color",
+  "pseudo color",
+  "true color",
+  "direct color",
+};
+
+#endif /* G_ENABLE_DEBUG */
+
+static GHashTable *visual_hash = NULL;
+
+void
+gdk_visual_init (void)
+{
+  struct
+  {
+    BITMAPINFOHEADER bi;
+    union
+    {
+      RGBQUAD colors[256];
+      DWORD fields[256];
+    } u;
+  } bmi;
+  HBITMAP hbm;
+
+  static const gint possible_depths[7] = { 32, 24, 16, 15, 8, 4, 1 };
+  static const GdkVisualType possible_types[6] =
+    {
+      GDK_VISUAL_DIRECT_COLOR,
+      GDK_VISUAL_TRUE_COLOR,
+      GDK_VISUAL_PSEUDO_COLOR,
+      GDK_VISUAL_STATIC_COLOR,
+      GDK_VISUAL_GRAYSCALE,
+      GDK_VISUAL_STATIC_GRAY
+    };
+
+  static const gint npossible_depths = sizeof(possible_depths)/sizeof(gint);
+  static const gint npossible_types = sizeof(possible_types)/sizeof(GdkVisualType);
+
+  int rastercaps, numcolors, sizepalette, colorres, bitspixel;
+  Visual *default_xvisual;
+  GdkVisualPrivate temp_visual;
+  int nxvisuals;
+  int i, j;
+
+  nxvisuals = 1;
+  visuals = g_new (GdkVisualPrivate, nxvisuals);
+
+  nvisuals = 0;
+  for (i = 0; i < nxvisuals; i++)
+    {
+      if (1)
+       {
+         bitspixel = GetDeviceCaps (gdk_DC, BITSPIXEL);
+         rastercaps = GetDeviceCaps (gdk_DC, RASTERCAPS);
+         default_xvisual = g_new (Visual, 1);
+         visuals[nvisuals].xvisual = default_xvisual;
+         visuals[nvisuals].xvisual->visualid = nvisuals;
+         visuals[nvisuals].xvisual->bitspixel = bitspixel;
+
+         if (rastercaps & RC_PALETTE)
+           {
+             visuals[nvisuals].visual.type = GDK_VISUAL_PSEUDO_COLOR;
+             numcolors = GetDeviceCaps (gdk_DC, NUMCOLORS);
+             sizepalette = GetDeviceCaps (gdk_DC, SIZEPALETTE);
+             colorres = GetDeviceCaps (gdk_DC, COLORRES);
+             visuals[nvisuals].xvisual->map_entries = sizepalette;
+           }
+         else if (bitspixel == 1)
+           {
+             visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_GRAY;
+             visuals[nvisuals].xvisual->map_entries = 2;
+           }
+         else if (bitspixel == 4)
+           {
+             visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR;
+             visuals[nvisuals].xvisual->map_entries = 16;
+           }
+         else if (bitspixel == 8)
+           {
+             visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR;
+             visuals[nvisuals].xvisual->map_entries = 256;
+           }
+         else if (bitspixel == 16)
+           {
+             visuals[nvisuals].visual.type = GDK_VISUAL_TRUE_COLOR;
+#if 1
+             /* This code by Mike Enright,
+              * see http://www.users.cts.com/sd/m/menright/display.html
+              */
+             memset (&bmi, 0, sizeof (bmi));
+             bmi.bi.biSize = sizeof (bmi.bi);
+  
+             hbm = CreateCompatibleBitmap (gdk_DC, 1, 1);
+             GetDIBits (gdk_DC, hbm, 0, 1, NULL,
+                        (BITMAPINFO *) &bmi, DIB_RGB_COLORS);
+             GetDIBits (gdk_DC, hbm, 0, 1, NULL,
+                        (BITMAPINFO *) &bmi, DIB_RGB_COLORS);
+             DeleteObject (hbm);
+
+             if (bmi.bi.biCompression != BI_BITFIELDS)
+               {
+                 /* Either BI_RGB or BI_RLE_something
+                  * .... or perhaps (!!) something else.
+                  * Theoretically biCompression might be
+                  * mmioFourCC('c','v','i','d') but I doubt it.
+                  */
+                 if (bmi.bi.biCompression == BI_RGB)
+                   {
+                     /* It's 555 */
+                     bitspixel = 15;
+                     visuals[nvisuals].visual.red_mask   = 0x00007C00;
+                     visuals[nvisuals].visual.green_mask = 0x000003E0;
+                     visuals[nvisuals].visual.blue_mask  = 0x0000001F;
+                   }
+                 else
+                   {
+                     g_assert_not_reached ();
+                   }
+               }
+             else
+               {
+                 DWORD allmasks =
+                   bmi.u.fields[0] | bmi.u.fields[1] | bmi.u.fields[2];
+                 int k = 0;
+                 while (allmasks)
+                   {
+                     if (allmasks&1)
+                       k++;
+                     allmasks/=2;
+                   }
+                 bitspixel = k;
+                 visuals[nvisuals].visual.red_mask = bmi.u.fields[0];
+                 visuals[nvisuals].visual.green_mask = bmi.u.fields[1];
+                 visuals[nvisuals].visual.blue_mask  = bmi.u.fields[2];
+               }
+#else
+             /* Old, incorrect (but still working) code. */
+#if 0
+             visuals[nvisuals].visual.red_mask   = 0x0000F800;
+             visuals[nvisuals].visual.green_mask = 0x000007E0;
+             visuals[nvisuals].visual.blue_mask  = 0x0000001F;
+#else
+             visuals[nvisuals].visual.red_mask   = 0x00007C00;
+             visuals[nvisuals].visual.green_mask = 0x000003E0;
+             visuals[nvisuals].visual.blue_mask  = 0x0000001F;
+#endif
+#endif
+           }
+         else if (bitspixel == 24 || bitspixel == 32)
+           {
+             visuals[nvisuals].visual.type = GDK_VISUAL_TRUE_COLOR;
+             visuals[nvisuals].visual.red_mask   = 0x00FF0000;
+             visuals[nvisuals].visual.green_mask = 0x0000FF00;
+             visuals[nvisuals].visual.blue_mask  = 0x000000FF;
+           }
+         else
+           g_error ("gdk_visual_init: unsupported BITSPIXEL: %d\n", bitspixel);
+
+         visuals[nvisuals].visual.depth = bitspixel;
+         visuals[nvisuals].visual.byte_order = GDK_LSB_FIRST;
+         visuals[nvisuals].visual.bits_per_rgb = 42; /* Not used? */
+
+         if ((visuals[nvisuals].visual.type == GDK_VISUAL_TRUE_COLOR) ||
+             (visuals[nvisuals].visual.type == GDK_VISUAL_DIRECT_COLOR))
+           {
+             gdk_visual_decompose_mask (visuals[nvisuals].visual.red_mask,
+                                        &visuals[nvisuals].visual.red_shift,
+                                        &visuals[nvisuals].visual.red_prec);
+
+             gdk_visual_decompose_mask (visuals[nvisuals].visual.green_mask,
+                                        &visuals[nvisuals].visual.green_shift,
+                                        &visuals[nvisuals].visual.green_prec);
+
+             gdk_visual_decompose_mask (visuals[nvisuals].visual.blue_mask,
+                                        &visuals[nvisuals].visual.blue_shift,
+                                        &visuals[nvisuals].visual.blue_prec);
+             visuals[nvisuals].xvisual->map_entries =
+               1 << (MAX (visuals[nvisuals].visual.red_prec,
+                          MAX (visuals[nvisuals].visual.green_prec,
+                               visuals[nvisuals].visual.blue_prec)));
+           }
+         else
+           {
+             visuals[nvisuals].visual.red_mask = 0;
+             visuals[nvisuals].visual.red_shift = 0;
+             visuals[nvisuals].visual.red_prec = 0;
+
+             visuals[nvisuals].visual.green_mask = 0;
+             visuals[nvisuals].visual.green_shift = 0;
+             visuals[nvisuals].visual.green_prec = 0;
+
+             visuals[nvisuals].visual.blue_mask = 0;
+             visuals[nvisuals].visual.blue_shift = 0;
+             visuals[nvisuals].visual.blue_prec = 0;
+           }
+         visuals[nvisuals].visual.colormap_size = visuals[nvisuals].xvisual->map_entries;
+
+         nvisuals += 1;
+       }
+    }
+
+  for (i = 0; i < nvisuals; i++)
+    {
+      for (j = i+1; j < nvisuals; j++)
+       {
+         if (visuals[j].visual.depth >= visuals[i].visual.depth)
+           {
+             if ((visuals[j].visual.depth == 8) && (visuals[i].visual.depth == 8))
+               {
+                 if (visuals[j].visual.type == GDK_VISUAL_PSEUDO_COLOR)
+                   {
+                     temp_visual = visuals[j];
+                     visuals[j] = visuals[i];
+                     visuals[i] = temp_visual;
+                   }
+                 else if ((visuals[i].visual.type != GDK_VISUAL_PSEUDO_COLOR) &&
+                          visuals[j].visual.type > visuals[i].visual.type)
+                   {
+                     temp_visual = visuals[j];
+                     visuals[j] = visuals[i];
+                     visuals[i] = temp_visual;
+                   }
+               }
+             else if ((visuals[j].visual.depth > visuals[i].visual.depth) ||
+                      ((visuals[j].visual.depth == visuals[i].visual.depth) &&
+                       (visuals[j].visual.type > visuals[i].visual.type)))
+               {
+                 temp_visual = visuals[j];
+                 visuals[j] = visuals[i];
+                 visuals[i] = temp_visual;
+               }
+           }
+       }
+    }
+
+  for (i = 0; i < nvisuals; i++)
+    if (default_xvisual->visualid == visuals[i].xvisual->visualid)
+      {
+       system_visual = &visuals[i];
+       break;
+      }
+
+  navailable_depths = 0;
+  for (i = 0; i < npossible_depths; i++)
+    {
+      for (j = 0; j < nvisuals; j++)
+       {
+         if (visuals[j].visual.depth == possible_depths[i])
+           {
+             available_depths[navailable_depths++] = visuals[j].visual.depth;
+             break;
+           }
+       }
+    }
+
+  if (navailable_depths == 0)
+    g_error ("unable to find a usable depth");
+
+  navailable_types = 0;
+  for (i = 0; i < npossible_types; i++)
+    {
+      for (j = 0; j < nvisuals; j++)
+       {
+         if (visuals[j].visual.type == possible_types[i])
+           {
+             available_types[navailable_types++] = visuals[j].visual.type;
+             break;
+           }
+       }
+    }
+
+  for (i = 0; i < nvisuals; i++)
+    gdk_visual_add ((GdkVisual*) &visuals[i]);
+
+  if (npossible_types == 0)
+    g_error ("unable to find a usable visual type");
+}
+
+GdkVisual*
+gdk_visual_ref (GdkVisual *visual)
+{
+  return visual;
+}
+
+void
+gdk_visual_unref (GdkVisual *visual)
+{
+  return;
+}
+
+gint
+gdk_visual_get_best_depth (void)
+{
+  return available_depths[0];
+}
+
+GdkVisualType
+gdk_visual_get_best_type (void)
+{
+  return available_types[0];
+}
+
+GdkVisual*
+gdk_visual_get_system (void)
+{
+  return ((GdkVisual*) system_visual);
+}
+
+GdkVisual*
+gdk_visual_get_best (void)
+{
+  return ((GdkVisual*) &(visuals[0]));
+}
+
+GdkVisual*
+gdk_visual_get_best_with_depth (gint depth)
+{
+  GdkVisual *return_val;
+  int i;
+
+  return_val = NULL;
+  for (i = 0; i < nvisuals; i++)
+    if (depth == visuals[i].visual.depth)
+      {
+       return_val = (GdkVisual*) &(visuals[i]);
+       break;
+      }
+
+  return return_val;
+}
+
+GdkVisual*
+gdk_visual_get_best_with_type (GdkVisualType visual_type)
+{
+  GdkVisual *return_val;
+  int i;
+
+  return_val = NULL;
+  for (i = 0; i < nvisuals; i++)
+    if (visual_type == visuals[i].visual.type)
+      {
+       return_val = (GdkVisual*) &(visuals[i]);
+       break;
+      }
+
+  return return_val;
+}
+
+GdkVisual*
+gdk_visual_get_best_with_both (gint          depth,
+                              GdkVisualType visual_type)
+{
+  GdkVisual *return_val;
+  int i;
+
+  return_val = NULL;
+  for (i = 0; i < nvisuals; i++)
+    if ((depth == visuals[i].visual.depth) &&
+       (visual_type == visuals[i].visual.type))
+      {
+       return_val = (GdkVisual*) &(visuals[i]);
+       break;
+      }
+
+  return return_val;
+}
+
+void
+gdk_query_depths  (gint **depths,
+                  gint  *count)
+{
+  *count = navailable_depths;
+  *depths = available_depths;
+}
+
+void
+gdk_query_visual_types (GdkVisualType **visual_types,
+                       gint           *count)
+{
+  *count = navailable_types;
+  *visual_types = available_types;
+}
+
+GList*
+gdk_list_visuals (void)
+{
+  GList *list;
+  guint i;
+
+  list = NULL;
+  for (i = 0; i < nvisuals; ++i)
+    list = g_list_append (list, (gpointer) &visuals[i]);
+
+  return list;
+}
+
+GdkVisual*
+gdk_visual_lookup (Visual *xvisual)
+{
+  GdkVisual *visual;
+
+  if (!visual_hash)
+    return NULL;
+
+  visual = g_hash_table_lookup (visual_hash, xvisual);
+  return visual;
+}
+
+GdkVisual*
+gdkx_visual_get (VisualID xvisualid)
+{
+  int i;
+
+  for (i = 0; i < nvisuals; i++)
+    if (xvisualid == visuals[i].xvisual->visualid)
+      return (GdkVisual*) &visuals[i];
+
+  return NULL;
+}
+
+static void
+gdk_visual_add (GdkVisual *visual)
+{
+  GdkVisualPrivate *private;
+
+  if (!visual_hash)
+    visual_hash = g_hash_table_new ((GHashFunc) gdk_visual_hash,
+                                   (GCompareFunc) gdk_visual_compare);
+
+  private = (GdkVisualPrivate*) visual;
+
+  g_hash_table_insert (visual_hash, private->xvisual, visual);
+}
+
+static void
+gdk_visual_decompose_mask (gulong  mask,
+                          gint   *shift,
+                          gint   *prec)
+{
+  *shift = 0;
+  *prec = 0;
+
+  while (!(mask & 0x1))
+    {
+      (*shift)++;
+      mask >>= 1;
+    }
+
+  while (mask & 0x1)
+    {
+      (*prec)++;
+      mask >>= 1;
+    }
+}
+
+/* This hash stuff is pretty useless on Windows, as there is only
+   one visual... */
+
+static guint
+gdk_visual_hash (Visual *key)
+{
+  return key->visualid;
+}
+
+static gint
+gdk_visual_compare (Visual *a,
+                   Visual *b)
+{
+  return (a->visualid == b->visualid);
+}
diff --git a/gdk/win32/gdkwin32.h b/gdk/win32/gdkwin32.h
new file mode 100644 (file)
index 0000000..5086191
--- /dev/null
@@ -0,0 +1,59 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GDK_X_H__
+#define __GDK_X_H__
+
+#include <gdk/gdk.h>
+#include <gdk/gdkprivate.h>
+
+#include <time.h>
+#include <locale.h>
+
+#define GDK_ROOT_WINDOW()             ((guint32) HWND_DESKTOP)
+#define GDK_ROOT_PARENT()             ((GdkWindow *)&gdk_root_parent)
+#define GDK_DISPLAY()                 NULL
+#define GDK_WINDOW_XDISPLAY(win)      NULL
+#define GDK_WINDOW_XWINDOW(win)       (((GdkWindowPrivate*) win)->xwindow)
+#define GDK_IMAGE_XDISPLAY(image)     NULL
+#define GDK_IMAGE_XIMAGE(image)       (((GdkImagePrivate*) image)->ximage)
+#define GDK_GC_XDISPLAY(gc)           NULL
+#define GDK_GC_XGC(gc)                (((GdkGCPrivate*) gc)->xgc)
+#define GDK_COLORMAP_XDISPLAY(cmap)   NULL
+#define GDK_COLORMAP_XCOLORMAP(cmap)  (((GdkColormapPrivate*) cmap)->xcolormap)
+#define GDK_VISUAL_XVISUAL(vis)       (((GdkVisualPrivate*) vis)->xvisual)
+#define GDK_FONT_XDISPLAY(font)       NULL
+#define GDK_FONT_XFONT(font)          (((GdkFontPrivate*) font)->xfont)
+
+GdkVisual*   gdkx_visual_get   (VisualID xvisualid);
+/* XXX: Do not use this function until it is fixed. An X Colormap
+ *      is useless unless we also have the visual. */
+GdkColormap* gdkx_colormap_get (Colormap xcolormap);
+/* Functions to create GDK pixmaps and windows from their native equivalents */
+GdkPixmap    *gdk_pixmap_foreign_new (guint32     anid);
+GdkWindow    *gdk_window_foreign_new (guint32       anid);
+
+#endif /* __GDK_X_H__ */
diff --git a/gdk/win32/gdkwin32id.c b/gdk/win32/gdkwin32id.c
new file mode 100644 (file)
index 0000000..f6d7bf0
--- /dev/null
@@ -0,0 +1,87 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include <stdio.h>
+
+static guint gdk_xid_hash    (XID *xid);
+static gint  gdk_xid_compare (XID *a,
+                             XID *b);
+
+
+static GHashTable *xid_ht = NULL;
+
+
+void
+gdk_xid_table_insert (XID      *xid,
+                     gpointer  data)
+{
+  g_return_if_fail (xid != NULL);
+
+  if (!xid_ht)
+    xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash,
+                              (GCompareFunc) gdk_xid_compare);
+
+  g_hash_table_insert (xid_ht, xid, data);
+}
+
+void
+gdk_xid_table_remove (XID xid)
+{
+  if (!xid_ht)
+    xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash,
+                              (GCompareFunc) gdk_xid_compare);
+
+  g_hash_table_remove (xid_ht, &xid);
+}
+
+gpointer
+gdk_xid_table_lookup (XID xid)
+{
+  gpointer data = NULL;
+
+  if (xid_ht)
+    data = g_hash_table_lookup (xid_ht, &xid);
+  
+  return data;
+}
+
+
+static guint
+gdk_xid_hash (XID *xid)
+{
+  return (guint) *xid;
+}
+
+static gint
+gdk_xid_compare (XID *a,
+                XID *b)
+{
+  return (*a == *b);
+}
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
new file mode 100644 (file)
index 0000000..02bbace
--- /dev/null
@@ -0,0 +1,2560 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-1999 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkinput.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+/* The Win API function AdjustWindowRect may return negative values
+ * resulting in obscured title bars. This helper function is coreccting it.
+ */
+BOOL AdjustWindowRectEx2(RECT* lpRect, 
+                         DWORD dwStyle, 
+                         BOOL bMenu, 
+                         DWORD dwExStyle)
+{
+  if (!AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle))
+    return FALSE;
+  if (lpRect->left < 0)
+    {
+      lpRect->right -= lpRect->left;
+      lpRect->left = 0;
+    }
+  if (lpRect->top < 0)
+    {
+      lpRect->bottom -= lpRect->top;
+      lpRect->top = 0;
+    }
+  return TRUE;
+}
+/* HB: now use it */
+#define AdjustWindowRectEx AdjustWindowRectEx2
+
+/* Forward declarations */
+static gboolean gdk_window_gravity_works (void);
+static void     gdk_window_set_static_win_gravity (GdkWindow *window, 
+                                                  gboolean   on);
+
+/* 
+ * The following fucntion by The Rasterman <raster@redhat.com>
+ * This function returns the X Window ID in which the x y location is in 
+ * (x and y being relative to the root window), excluding any windows listed
+ * in the GList excludes (this is a list of X Window ID's - gpointer being
+ * the Window ID).
+ * 
+ * This is primarily designed for internal gdk use - for DND for example
+ * when using a shaped icon window as the drag object - you exclude the
+ * X Window ID of the "icon" (perhaps more if excludes may be needed) and
+ * You can get back an X Window ID as to what X Window ID is infact under
+ * those X,Y co-ordinates.
+ */
+HWND
+gdk_window_xid_at_coords (gint     x,
+                         gint     y,
+                         GList   *excludes,
+                         gboolean excl_child)
+{
+  POINT pt;
+  gboolean warned = FALSE;
+
+  pt.x = x;
+  pt.y = y;
+  /* This is probably not correct, just a quick hack */
+
+  if (!warned)
+    {
+      g_warning ("gdk_window_xid_at_coords probably not implemented correctly");
+      warned = TRUE;
+    }
+
+  /* XXX */
+  return WindowFromPoint (pt);
+}
+
+void
+gdk_window_init (void)
+{
+  unsigned int width;
+  unsigned int height;
+#if 0
+  width = GetSystemMetrics (SM_CXSCREEN);
+  height = GetSystemMetrics (SM_CYSCREEN);
+#else
+  { RECT r; /* //HB: don't obscure tray window (task bar) */
+    SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
+    width  = r.right - r.left;
+    height = r.bottom - r.top;
+  }
+#endif
+
+  gdk_root_parent.xwindow = gdk_root_window;
+  gdk_root_parent.window_type = GDK_WINDOW_ROOT;
+  gdk_root_parent.window.user_data = NULL;
+  gdk_root_parent.width = width;
+  gdk_root_parent.height = height;
+  gdk_root_parent.children = NULL;
+  gdk_root_parent.colormap = NULL;
+  gdk_root_parent.ref_count = 1;
+
+  gdk_xid_table_insert (&gdk_root_window, &gdk_root_parent);
+}
+
+GdkWindow*
+gdk_window_new (GdkWindow     *parent,
+               GdkWindowAttr *attributes,
+               gint           attributes_mask)
+{
+  GdkWindow *window;
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *parent_private;
+  GdkVisual *visual;
+  HANDLE xparent;
+  Visual *xvisual;
+#ifdef MULTIPLE_WINDOW_CLASSES
+  WNDCLASSEX wcl; 
+  ATOM klass;
+  char wcl_name_buf[20];
+  static int wcl_cnt = 0;
+#else
+  static WNDCLASSEX wcl; 
+  static ATOM klass = 0;
+#endif
+  static HICON hAppIcon = NULL;
+  DWORD dwStyle, dwExStyle;
+  RECT rect;
+  int width, height;
+  int x, y;
+  char *title;
+
+  g_return_val_if_fail (attributes != NULL, NULL);
+
+  if (!parent)
+    parent = (GdkWindow*) &gdk_root_parent;
+
+  parent_private = (GdkWindowPrivate*) parent;
+  if (parent_private->destroyed)
+    return NULL;
+
+  xparent = parent_private->xwindow;
+
+  private = g_new (GdkWindowPrivate, 1);
+  window = (GdkWindow*) private;
+
+  private->parent = parent;
+
+  private->destroyed = FALSE;
+  private->mapped = FALSE;
+  private->guffaw_gravity = FALSE;
+  private->resize_count = 0;
+  private->ref_count = 1;
+
+  if (attributes_mask & GDK_WA_X)
+    x = attributes->x;
+  else
+    x = 0;
+
+  if (attributes_mask & GDK_WA_Y)
+    y = attributes->y;
+  else
+    y = 0;
+
+  private->x = x;
+  private->y = y;
+  private->width = (attributes->width > 1) ? (attributes->width) : (1);
+  private->height = (attributes->height > 1) ? (attributes->height) : (1);
+  private->window_type = attributes->window_type;
+  private->extension_events = 0;
+  private->extension_events_selected = FALSE;
+
+  private->filters = NULL;
+  private->children = NULL;
+
+  window->user_data = NULL;
+
+  if (attributes_mask & GDK_WA_VISUAL)
+    visual = attributes->visual;
+  else
+    visual = gdk_visual_get_system ();
+  xvisual = ((GdkVisualPrivate*) visual)->xvisual;
+
+  if (attributes_mask & GDK_WA_TITLE)
+    title = attributes->title;
+  else
+    title = g_get_prgname ();
+
+  private->event_mask = GDK_STRUCTURE_MASK | attributes->event_mask;
+  private->bg_type = GDK_WIN32_BG_NORMAL;
+  private->hint_flags = 0;
+  
+#ifndef MULTIPLE_WINDOW_CLASSES
+  if (klass == 0)
+    {
+#endif
+  wcl.cbSize = sizeof (WNDCLASSEX);
+#if 1
+  wcl.style = CS_HREDRAW | CS_VREDRAW;
+#else
+  wcl.style = 0;
+#endif
+  wcl.lpfnWndProc = gdk_WindowProc;
+  wcl.cbClsExtra = 0;
+  wcl.cbWndExtra = 0;
+  wcl.hInstance = gdk_ProgInstance;
+  wcl.hCursor = LoadCursor (NULL, IDC_ARROW);
+
+#if 0 /* tml: orig -> generates SetClassLong errors in set background */
+  wcl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
+  wcl.hbrBackground = NULL;
+#else
+  /* initialize once! */
+  if (0 == hAppIcon)
+    {
+      gchar sLoc [_MAX_PATH+1];
+      HINSTANCE hInst = GetModuleHandle(NULL);
+
+      if (0 != GetModuleFileName(hInst, sLoc, _MAX_PATH))
+       {
+         hAppIcon = ExtractIcon(hInst, sLoc, 0);
+         if (0 == hAppIcon)
+           {
+             char *gdklibname = g_strdup_printf ("gdk-%s.dll", GDK_VERSION);
+
+             hAppIcon = ExtractIcon(hInst, gdklibname, 0);
+             g_free (gdklibname);
+           }
+         
+         if (0 == hAppIcon) 
+           hAppIcon = LoadIcon (NULL, IDI_APPLICATION);
+       }
+    }
+  wcl.hIcon = CopyIcon (hAppIcon);
+  wcl.hIconSm = CopyIcon (hAppIcon);
+  /* HB: starting with black to have something to release ... */
+  wcl.hbrBackground = CreateSolidBrush( RGB(0,0,0));
+#endif
+
+  wcl.lpszMenuName = NULL;
+#ifdef MULTIPLE_WINDOW_CLASSES
+  sprintf (wcl_name_buf, "gdk-wcl-%d", wcl_cnt++);
+  wcl.lpszClassName = g_strdup (wcl_name_buf);
+  /* wcl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); */
+#else
+  wcl.lpszClassName = "GDK-window-class";
+  klass = RegisterClassEx (&wcl);
+  if (!klass)
+    g_error ("RegisterClassEx failed");
+    }
+
+  private->xcursor = NULL;
+#endif
+      
+  if (parent_private && parent_private->guffaw_gravity)
+    {
+      /* XXX ??? */
+    }
+
+  if (attributes->wclass == GDK_INPUT_OUTPUT)
+    {
+      dwExStyle = 0;
+      if (attributes_mask & GDK_WA_COLORMAP)
+       private->colormap = attributes->colormap;
+      else
+       private->colormap = gdk_colormap_get_system ();
+    }
+  else
+    {
+      dwExStyle = WS_EX_TRANSPARENT;
+      private->colormap = NULL;
+      private->bg_type = GDK_WIN32_BG_TRANSPARENT;
+      private->bg_pixmap = NULL;
+    }
+
+  if (attributes_mask & GDK_WA_X)
+    x = attributes->x;
+  else
+    x = CW_USEDEFAULT;
+
+  if (attributes_mask & GDK_WA_Y)
+    y = attributes->y;
+  else if (attributes_mask & GDK_WA_X)
+    y = 100;                   /* ??? We must put it somewhere... */
+  else
+    y = 500;                   /* x is CW_USEDEFAULT, y doesn't matter then */
+
+  if (parent_private)
+    parent_private->children = g_list_prepend (parent_private->children, window);
+
+  switch (private->window_type)
+    {
+    case GDK_WINDOW_TOPLEVEL:
+      dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
+      xparent = gdk_root_window;
+      break;
+    case GDK_WINDOW_CHILD:
+      dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+      break;
+    case GDK_WINDOW_DIALOG:
+      dwStyle = WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN;
+      xparent = gdk_root_window;
+      break;
+    case GDK_WINDOW_TEMP:
+      dwStyle = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+#ifdef MULTIPLE_WINDOW_CLASSES
+      wcl.style |= CS_SAVEBITS;
+#endif
+      dwExStyle |= WS_EX_TOOLWINDOW;
+      break;
+    case GDK_WINDOW_ROOT:
+      g_error ("cannot make windows of type GDK_WINDOW_ROOT");
+      break;
+    case GDK_WINDOW_PIXMAP:
+      g_error ("cannot make windows of type GDK_WINDOW_PIXMAP (use gdk_pixmap_new)");
+      break;
+    }
+
+#ifdef MULTIPLE_WINDOW_CLASSES
+  klass = RegisterClassEx (&wcl);
+  if (!klass)
+    g_error ("RegisterClassEx failed");
+#endif
+
+  if (private->window_type != GDK_WINDOW_CHILD)
+    {
+      if (x == CW_USEDEFAULT)
+       {
+         rect.left = 100;
+         rect.top = 100;
+       }
+      else
+       {
+         rect.left = x;
+         rect.top = y;
+       }
+
+      rect.right = rect.left + private->width;
+      rect.bottom = rect.top + private->height;
+
+      if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle))
+       g_warning ("gdk_window_new: AdjustWindowRectEx failed");
+
+      if (x != CW_USEDEFAULT)
+       {
+         x = rect.left;
+         y = rect.top;
+       }
+      width = rect.right - rect.left;
+      height = rect.bottom - rect.top;
+    }
+  else
+    {
+      width = private->width;
+      height = private->height;
+    }
+
+  private->xwindow =
+    CreateWindowEx (dwExStyle,
+                   wcl.lpszClassName,
+                   title,
+                   dwStyle,
+                   x, y, 
+                   width, height,
+                   xparent,
+                   NULL,
+                   gdk_ProgInstance,
+                   NULL);
+  GDK_NOTE (MISC,
+           g_print ("gdk_window_create: %s %s %#x %dx%d@+%d+%d %#x = %#x\n",
+                    (private->window_type == GDK_WINDOW_TOPLEVEL ? "TOPLEVEL" :
+                     (private->window_type == GDK_WINDOW_CHILD ? "CHILD" :
+                      (private->window_type == GDK_WINDOW_DIALOG ? "DIALOG" :
+                       (private->window_type == GDK_WINDOW_TEMP ? "TEMP" :
+                        "???")))),
+                    title,
+                    dwStyle,
+                    width, height, (x == CW_USEDEFAULT ? -9999 : x), y, 
+                    xparent,
+                    private->xwindow));
+
+  gdk_window_ref (window);
+  gdk_xid_table_insert (&private->xwindow, window);
+
+  if (private->colormap)
+    gdk_colormap_ref (private->colormap);
+
+  gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
+                                 (attributes->cursor) :
+                                 NULL));
+
+  return window;
+}
+
+GdkWindow *
+gdk_window_foreign_new (guint32 anid)
+{
+  GdkWindow *window;
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *parent_private;
+  HANDLE parent;
+  RECT rect;
+  POINT point;
+
+  private = g_new (GdkWindowPrivate, 1);
+  window = (GdkWindow*) private;
+
+  parent = GetParent ((HWND) anid);
+  private->parent = gdk_xid_table_lookup (parent);
+
+  parent_private = (GdkWindowPrivate *)private->parent;
+  
+  if (parent_private)
+    parent_private->children = g_list_prepend (parent_private->children, window);
+
+  private->xwindow = (HWND) anid;
+  GetClientRect ((HWND) anid, &rect);
+  point.x = rect.left;
+  point.y = rect.right;
+  ClientToScreen ((HWND) anid, &point);
+  if (parent != HWND_DESKTOP)
+    ScreenToClient (parent, &point);
+  private->x = point.x;
+  private->y = point.y;
+  private->width = rect.right - rect.left;
+  private->height = rect.bottom - rect.top;
+  private->resize_count = 0;
+  private->ref_count = 1;
+  private->window_type = GDK_WINDOW_FOREIGN;
+  private->destroyed = FALSE;
+  private->mapped = IsWindowVisible (private->xwindow);
+  private->guffaw_gravity = FALSE;
+  private->extension_events = 0;
+  private->extension_events_selected = FALSE;
+
+  private->colormap = NULL;
+
+  private->filters = NULL;
+  private->children = NULL;
+
+  window->user_data = NULL;
+
+  gdk_window_ref (window);
+  gdk_xid_table_insert (&private->xwindow, window);
+
+  return window;
+}
+
+/* Call this function when you want a window and all its children to
+ * disappear.  When xdestroy is true, a request to destroy the XWindow
+ * is sent out.  When it is false, it is assumed that the XWindow has
+ * been or will be destroyed by destroying some ancestor of this
+ * window.
+ */
+static void
+gdk_window_internal_destroy (GdkWindow *window,
+                            gboolean   xdestroy,
+                            gboolean   our_destroy)
+{
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *temp_private;
+  GdkWindow *temp_window;
+  GList *children;
+  GList *tmp;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+
+  GDK_NOTE (MISC, g_print ("gdk_window_internal_destroy %#x\n",
+                          private->xwindow));
+
+  switch (private->window_type)
+    {
+    case GDK_WINDOW_TOPLEVEL:
+    case GDK_WINDOW_CHILD:
+    case GDK_WINDOW_DIALOG:
+    case GDK_WINDOW_TEMP:
+    case GDK_WINDOW_FOREIGN:
+      if (!private->destroyed)
+       {
+         if (private->parent)
+           {
+             GdkWindowPrivate *parent_private = (GdkWindowPrivate *)private->parent;
+             if (parent_private->children)
+               parent_private->children = g_list_remove (parent_private->children, window);
+           }
+
+         if (private->window_type != GDK_WINDOW_FOREIGN)
+           {
+             children = tmp = private->children;
+             private->children = NULL;
+
+             while (tmp)
+               {
+                 temp_window = tmp->data;
+                 tmp = tmp->next;
+                 
+                 temp_private = (GdkWindowPrivate*) temp_window;
+                 if (temp_private)
+                   gdk_window_internal_destroy (temp_window, FALSE,
+                                                our_destroy);
+               }
+
+             g_list_free (children);
+           }
+
+         if (private->extension_events != 0)
+           gdk_input_window_destroy (window);
+
+         if (private->filters)
+           {
+             tmp = private->filters;
+
+             while (tmp)
+               {
+                 g_free (tmp->data);
+                 tmp = tmp->next;
+               }
+
+             g_list_free (private->filters);
+             private->filters = NULL;
+           }
+         
+         if (private->window_type == GDK_WINDOW_FOREIGN)
+           {
+             if (our_destroy && (private->parent != NULL))
+               {
+                 /* It's somebody elses window, but in our hierarchy,
+                  * so reparent it to the root window, and then send
+                  * it a delete event, as if we were a WM
+                  */
+                 gdk_window_hide (window);
+                 gdk_window_reparent (window, NULL, 0, 0);
+                 
+                 /* Is this too drastic? Many (most?) applications
+                  * quit if any window receives WM_QUIT I think.
+                  * OTOH, I don't think foreign windows are much
+                  * used, so the question is maybe academic.
+                  */
+                 PostMessage (private->xwindow, WM_QUIT, 0, 0);
+               }
+           }
+         else if (xdestroy)
+           DestroyWindow (private->xwindow);
+
+         if (private->colormap)
+           gdk_colormap_unref (private->colormap);
+
+         private->mapped = FALSE;
+         private->destroyed = TRUE;
+       }
+      break;
+
+    case GDK_WINDOW_ROOT:
+      g_error ("attempted to destroy root window");
+      break;
+
+    case GDK_WINDOW_PIXMAP:
+      g_error ("called gdk_window_destroy on a pixmap (use gdk_pixmap_unref)");
+      break;
+    }
+}
+
+/* Like internal_destroy, but also destroys the reference created by
+   gdk_window_new. */
+
+void
+gdk_window_destroy (GdkWindow *window)
+{
+  gdk_window_internal_destroy (window, TRUE, TRUE);
+  gdk_window_unref (window);
+}
+
+/* This function is called when the XWindow is really gone.  */
+
+void
+gdk_window_destroy_notify (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+
+  GDK_NOTE (EVENTS, g_print ("gdk_window_destroy_notify: %#x  %d\n",
+                            private->xwindow, private->destroyed));
+
+  if (!private->destroyed)
+    {
+      if (private->window_type == GDK_WINDOW_FOREIGN)
+       gdk_window_internal_destroy (window, FALSE, FALSE);
+      else
+       g_warning ("GdkWindow %#lx unexpectedly destroyed", private->xwindow);
+    }
+  
+  gdk_xid_table_remove (private->xwindow);
+  gdk_window_unref (window);
+}
+
+GdkWindow*
+gdk_window_ref (GdkWindow *window)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+  g_return_val_if_fail (window != NULL, NULL);
+
+  private->ref_count += 1;
+
+  GDK_NOTE (MISC, g_print ("gdk_window_ref %#x %d\n",
+                          private->xwindow, private->ref_count));
+
+  return window;
+}
+
+void
+gdk_window_unref (GdkWindow *window)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+  g_return_if_fail (window != NULL);
+
+  private->ref_count -= 1;
+
+  GDK_NOTE (MISC, g_print ("gdk_window_unref %#x %d%s\n",
+                          private->xwindow, private->ref_count,
+                          (private->ref_count == 0 ? " freeing" : "")));
+
+  if (private->ref_count == 0)
+    {
+      if (private->bg_type == GDK_WIN32_BG_PIXMAP && private->bg_pixmap != NULL)
+       gdk_pixmap_unref (private->bg_pixmap);
+
+      if (!private->destroyed)
+       {
+         if (private->window_type == GDK_WINDOW_FOREIGN)
+           gdk_xid_table_remove (private->xwindow);
+         else
+           g_warning ("losing last reference to undestroyed window");
+       }
+      g_dataset_destroy (window);
+      g_free (window);
+    }
+}
+
+void
+gdk_window_show (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_show: %#x\n", private->xwindow));
+
+      private->mapped = TRUE;
+      if (private->window_type == GDK_WINDOW_TEMP)
+       {
+         ShowWindow (private->xwindow, SW_SHOWNOACTIVATE);
+         SetWindowPos (private->xwindow, HWND_TOPMOST, 0, 0, 0, 0,
+                       SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+#if 0
+         ShowWindow (private->xwindow, SW_HIDE); /* Don't put on toolbar */
+#endif
+       }
+      else
+       {
+         ShowWindow (private->xwindow, SW_SHOWNORMAL);
+         ShowWindow (private->xwindow, SW_RESTORE);
+         SetForegroundWindow (private->xwindow);
+#if 0
+         ShowOwnedPopups (private->xwindow, TRUE);
+#endif
+       }
+    }
+}
+
+void
+gdk_window_hide (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_hide: %#x\n", private->xwindow));
+
+      private->mapped = FALSE;
+      if (private->window_type == GDK_WINDOW_TOPLEVEL)
+       ShowOwnedPopups (private->xwindow, FALSE);
+#if 1
+      ShowWindow (private->xwindow, SW_HIDE);
+#elif 0
+      ShowWindow (private->xwindow, SW_MINIMIZE);
+#else
+      CloseWindow (private->xwindow);
+#endif
+    }
+}
+
+void
+gdk_window_withdraw (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_withdraw: %#x\n", private->xwindow));
+
+      gdk_window_hide (window);        /* XXX */
+    }
+}
+
+void
+gdk_window_move (GdkWindow *window,
+                gint       x,
+                gint       y)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      RECT rect;
+      DWORD dwStyle;
+      DWORD dwExStyle;
+
+      GDK_NOTE (MISC, g_print ("gdk_window_move: %#x +%d+%d\n",
+                              private->xwindow, x, y));
+      GetClientRect (private->xwindow, &rect);
+
+      dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+      dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+      if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle))
+       g_warning ("gdk_window_move: AdjustWindowRectEx failed");
+      if (private->window_type == GDK_WINDOW_CHILD)
+       {
+         private->x = x;
+         private->y = y;
+       }
+      GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n",
+                              private->xwindow,
+                              rect.right - rect.left, rect.bottom - rect.top,
+                              x + rect.left, y + rect.top));
+      if (!MoveWindow (private->xwindow,
+                      x + rect.left, y + rect.top,
+                      rect.right - rect.left, rect.bottom - rect.top,
+                      TRUE))
+       g_warning ("gdk_window_move: MoveWindow failed");
+    }
+}
+
+void
+gdk_window_resize (GdkWindow *window,
+                  gint       width,
+                  gint       height)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  if ((gint16) width < 1)
+    width = 1;
+  if ((gint16) height < 1)
+    height = 1;
+
+  private = (GdkWindowPrivate*) window;
+
+  if (!private->destroyed &&
+      ((private->resize_count > 0) ||
+       (private->width != (guint16) width) ||
+       (private->height != (guint16) height)))
+    {
+      RECT rect;
+      POINT pt;
+      DWORD dwStyle;
+      DWORD dwExStyle;
+      int x, y;
+
+      GDK_NOTE (MISC, g_print ("gdk_window_resize: %#x %dx%d\n",
+                              private->xwindow, width, height));
+      
+      pt.x = 0;
+      pt.y = 0; 
+      ClientToScreen (private->xwindow, &pt);
+      rect.left = pt.x;
+      rect.top = pt.y;
+      rect.right = pt.x + width;
+      rect.bottom = pt.y + height;
+
+      dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+      dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+      if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle))
+       g_warning ("gdk_window_resize: AdjustWindowRectEx failed");
+      if (private->window_type != GDK_WINDOW_CHILD)
+       {
+         x = rect.left;
+         y = rect.top;
+       }
+      else
+       {
+         x = private->x;
+         y = private->y;
+       }
+
+      private->resize_count += 1;
+
+      if (private->window_type == GDK_WINDOW_CHILD)
+       {
+         private->width = width;
+         private->height = height;
+       }
+      GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n",
+                              private->xwindow,
+                              rect.right - rect.left, rect.bottom - rect.top,
+                              x, y));
+      if (!MoveWindow (private->xwindow,
+                      x, y,
+                      rect.right - rect.left, rect.bottom - rect.top,
+                      TRUE))
+       g_warning ("gdk_window_resize: MoveWindow failed");
+    }
+}
+
+void
+gdk_window_move_resize (GdkWindow *window,
+                       gint       x,
+                       gint       y,
+                       gint       width,
+                       gint       height)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  if ((gint16) width < 1)
+    width = 1;
+  if ((gint16) height < 1)
+    height = 1;
+
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      RECT rect;
+      DWORD dwStyle;
+      DWORD dwExStyle;
+
+      GDK_NOTE (MISC, g_print ("gdk_window_move_resize: %#x %dx%d@+%d+%d\n",
+                              private->xwindow, width, height, x, y));
+      
+      rect.left = x;
+      rect.top = y;
+      rect.right = x + width;
+      rect.bottom = y + height;
+
+      dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+      dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+      if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle))
+       g_warning ("gdk_window_move_resize: AdjustWindowRectEx failed");
+
+      if (private->window_type == GDK_WINDOW_CHILD)
+       {
+         private->x = x;
+         private->y = y;
+         private->width = width;
+         private->height = height;
+       }
+      GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n",
+                              private->xwindow,
+                              rect.right - rect.left, rect.bottom - rect.top,
+                              rect.left, rect.top));
+      if (!MoveWindow (private->xwindow,
+                      rect.left, rect.top,
+                      rect.right - rect.left, rect.bottom - rect.top,
+                      TRUE))
+       g_warning ("gdk_window_move_resize: MoveWindow failed");
+
+      if (private->guffaw_gravity)
+       {
+         GList *tmp_list = private->children;
+         while (tmp_list)
+           {
+             GdkWindowPrivate *child_private = tmp_list->data;
+             
+             child_private->x -= x - private->x;
+             child_private->y -= y - private->y;
+             
+             tmp_list = tmp_list->next;
+           }
+       }
+      
+    }
+}
+
+void
+gdk_window_reparent (GdkWindow *window,
+                    GdkWindow *new_parent,
+                    gint       x,
+                    gint       y)
+{
+  GdkWindowPrivate *window_private;
+  GdkWindowPrivate *parent_private;
+  GdkWindowPrivate *old_parent_private;
+
+  g_return_if_fail (window != NULL);
+
+  if (!new_parent)
+    new_parent = (GdkWindow*) &gdk_root_parent;
+
+  window_private = (GdkWindowPrivate*) window;
+  old_parent_private = (GdkWindowPrivate*)window_private->parent;
+  parent_private = (GdkWindowPrivate*) new_parent;
+
+  if (!window_private->destroyed && !parent_private->destroyed)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_reparent: %#x %#x\n",
+                              window_private->xwindow,
+                              parent_private->xwindow));
+      if (!SetParent (window_private->xwindow, parent_private->xwindow))
+       g_warning ("gdk_window_reparent: SetParent failed");
+
+      if (!MoveWindow (window_private->xwindow,
+                      x, y,
+                      window_private->width, window_private->height,
+                      TRUE))
+       g_warning ("gdk_window_reparent: MoveWindow failed");
+    }
+  
+  window_private->parent = new_parent;
+
+  if (old_parent_private)
+    old_parent_private->children = g_list_remove (old_parent_private->children, window);
+
+  if ((old_parent_private &&
+       (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) ||
+      (!old_parent_private && parent_private->guffaw_gravity))
+    gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity);
+  
+  parent_private->children = g_list_prepend (parent_private->children, window);
+}
+
+void
+gdk_window_clear (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+
+  if (!private->destroyed)
+    {
+      gdk_window_clear_area (window, 0, 0, private->width, private->height);
+    }
+}
+
+
+void
+gdk_window_clear_area (GdkWindow *window,
+                      gint       x,
+                      gint       y,
+                      gint       width,
+                      gint       height)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  
+  if (!private->destroyed)
+    {
+      HDC hdc;
+
+      if (width == -1)
+       width = G_MAXSHORT/2;           /* Yeah, right */
+      if (height == -1)
+       height = G_MAXSHORT/2;
+      GDK_NOTE (MISC, g_print ("gdk_window_clear_area: %#x %dx%d@+%d+%d\n",
+                              private->xwindow, width, height, x, y));
+      hdc = GetDC (private->xwindow);
+      IntersectClipRect (hdc, x, y, x + width, y + height);
+      SendMessage (private->xwindow, WM_ERASEBKGND, (WPARAM) hdc, 0);
+      ReleaseDC (private->xwindow, hdc);
+    }
+}
+
+void
+gdk_window_clear_area_e (GdkWindow *window,
+                        gint       x,
+                        gint       y,
+                        gint       width,
+                        gint       height)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  
+  if (!private->destroyed)
+    {
+      RECT rect;
+
+      GDK_NOTE (MISC, g_print ("gdk_window_clear_area_e: %#x %dx%d@+%d+%d\n",
+                              private->xwindow, width, height, x, y));
+
+      rect.left = x;
+      rect.right = x + width;
+      rect.top = y;
+      rect.bottom = y + height;
+      if (!InvalidateRect (private->xwindow, &rect, TRUE))
+       g_warning ("gdk_window_clear_area_e: InvalidateRect failed");
+      UpdateWindow (private->xwindow);
+    }
+}
+
+void
+gdk_window_copy_area (GdkWindow    *window,
+                     GdkGC        *gc,
+                     gint          x,
+                     gint          y,
+                     GdkWindow    *source_window,
+                     gint          source_x,
+                     gint          source_y,
+                     gint          width,
+                     gint          height)
+{
+  GdkWindowPrivate *src_private;
+  GdkWindowPrivate *dest_private;
+  GdkGCPrivate *gc_private;
+  
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (gc != NULL);
+  
+  if (source_window == NULL)
+    source_window = window;
+  
+  src_private = (GdkWindowPrivate*) source_window;
+  dest_private = (GdkWindowPrivate*) window;
+  gc_private = (GdkGCPrivate*) gc;
+  
+  if (!src_private->destroyed && !dest_private->destroyed)
+    {
+      HDC hdcDest, hdcSrc;
+
+      if ((hdcDest = GetDC (dest_private->xwindow)) == NULL)
+       g_warning ("gdk_window_copy_area: GetDC failed");
+
+      if ((hdcSrc = GetDC (src_private->xwindow)) == NULL)
+       g_warning ("gdk_window_copy_area: GetDC failed");
+
+      if (!BitBlt (hdcDest, x, y, width, height, hdcSrc, source_x, source_y, SRCCOPY))
+       g_warning ("gdk_window_copy_area: BitBlt failed");
+
+      ReleaseDC (dest_private->xwindow, hdcDest);
+      ReleaseDC (src_private->xwindow, hdcSrc);
+    }
+}
+
+void
+gdk_window_raise (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  
+  if (!private->destroyed)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_raise: %#x\n", private->xwindow));
+
+      if (!BringWindowToTop (private->xwindow))
+       g_warning ("gdk_window_raise: BringWindowToTop failed");
+    }
+}
+
+void
+gdk_window_lower (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  
+  if (!private->destroyed)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_lower: %#x\n", private->xwindow));
+
+      if (!SetWindowPos (private->xwindow, HWND_BOTTOM, 0, 0, 0, 0,
+                        SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE))
+       g_warning ("gdk_window_lower: SetWindowPos failed");
+    }
+}
+
+void
+gdk_window_set_user_data (GdkWindow *window,
+                         gpointer   user_data)
+{
+  g_return_if_fail (window != NULL);
+  
+  window->user_data = user_data;
+}
+
+void
+gdk_window_set_hints (GdkWindow *window,
+                     gint       x,
+                     gint       y,
+                     gint       min_width,
+                     gint       min_height,
+                     gint       max_width,
+                     gint       max_height,
+                     gint       flags)
+{
+  GdkWindowPrivate *private;
+  WINDOWPLACEMENT size_hints;
+  RECT rect;
+  DWORD dwStyle;
+  DWORD dwExStyle;
+  int diff;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return;
+  
+  GDK_NOTE (MISC, g_print ("gdk_window_set_hints: %#x %dx%d..%dx%d @+%d+%d\n",
+                          private->xwindow,
+                          min_width, min_height, max_width, max_height,
+                          x, y));
+
+  private->hint_flags = flags;
+  size_hints.length = sizeof (size_hints);
+
+  if (flags)
+    {
+      if (flags & GDK_HINT_POS)
+       if (!GetWindowPlacement (private->xwindow, &size_hints))
+         g_warning ("gdk_window_set_hints: GetWindowPlacement failed");
+       else
+         {
+           GDK_NOTE (MISC, g_print ("...rcNormalPosition:"
+                                    " (%d,%d)--(%d,%d)\n",
+                                    size_hints.rcNormalPosition.left,
+                                    size_hints.rcNormalPosition.top,
+                                    size_hints.rcNormalPosition.right,
+                                    size_hints.rcNormalPosition.bottom));
+           /* What are the corresponding window coordinates for client
+            * area coordinates x, y
+            */
+           rect.left = x;
+           rect.top = y;
+           rect.right = rect.left + 200;       /* dummy */
+           rect.bottom = rect.top + 200;
+           dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+           dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+           AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+           size_hints.flags = 0;
+           size_hints.showCmd = SW_SHOWNA;
+
+           /* Set the normal position hint to that location, with unchanged
+            * width and height.
+            */
+           diff = size_hints.rcNormalPosition.left - rect.left;
+           size_hints.rcNormalPosition.left = rect.left;
+           size_hints.rcNormalPosition.right -= diff;
+           diff = size_hints.rcNormalPosition.top - rect.top;
+           size_hints.rcNormalPosition.top = rect.top;
+           size_hints.rcNormalPosition.bottom -= diff;
+           GDK_NOTE (MISC, g_print ("...setting: (%d,%d)--(%d,%d)\n",
+                                    size_hints.rcNormalPosition.left,
+                                    size_hints.rcNormalPosition.top,
+                                    size_hints.rcNormalPosition.right,
+                                    size_hints.rcNormalPosition.bottom));
+           if (!SetWindowPlacement (private->xwindow, &size_hints))
+             g_warning ("gdk_window_set_hints: SetWindowPlacement failed");
+           private->hint_x = rect.left;
+           private->hint_y = rect.top;
+         }
+
+      if (flags & GDK_HINT_MIN_SIZE)
+       {
+         rect.left = 0;
+         rect.top = 0;
+         rect.right = min_width;
+         rect.bottom = min_height;
+         dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+         dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+         AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+         private->hint_min_width = rect.right - rect.left;
+         private->hint_min_height = rect.bottom - rect.top;
+
+         /* Also chek if he current size of the window is in bounds. */
+         GetClientRect (private->xwindow, &rect);
+         if (rect.right < min_width && rect.bottom < min_height)
+           gdk_window_resize (window, min_width, min_height);
+         else if (rect.right < min_width)
+           gdk_window_resize (window, min_width, rect.bottom);
+         else if (rect.bottom < min_height)
+           gdk_window_resize (window, rect.right, min_height);
+       }
+      if (flags & GDK_HINT_MAX_SIZE)
+       {
+         rect.left = 0;
+         rect.top = 0;
+         rect.right = max_width;
+         rect.bottom = max_height;
+         dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+         dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+         AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+         private->hint_max_width = rect.right - rect.left;
+         private->hint_max_height = rect.bottom - rect.top;
+         /* Again, check if the window is too large currently. */
+         GetClientRect (private->xwindow, &rect);
+         if (rect.right > max_width && rect.bottom > max_height)
+           gdk_window_resize (window, max_width, max_height);
+         else if (rect.right > max_width)
+           gdk_window_resize (window, max_width, rect.bottom);
+         else if (rect.bottom > max_height)
+           gdk_window_resize (window, rect.right, max_height);
+       }
+    }
+}
+
+void 
+gdk_window_set_geometry_hints (GdkWindow      *window,
+                              GdkGeometry    *geometry,
+                              GdkWindowHints  geom_mask)
+{
+  GdkWindowPrivate *private;
+  WINDOWPLACEMENT size_hints;
+  RECT rect;
+  DWORD dwStyle;
+  DWORD dwExStyle;
+  int diff;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return;
+  
+  size_hints.length = sizeof (size_hints);
+
+  private->hint_flags = geom_mask;
+
+  if (geom_mask & GDK_HINT_POS)
+    ; /* XXX */
+
+  if (geom_mask & GDK_HINT_MIN_SIZE)
+    {
+      rect.left = 0;
+      rect.top = 0;
+      rect.right = geometry->min_width;
+      rect.bottom = geometry->min_height;
+      dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+      dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+      AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+      private->hint_min_width = rect.right - rect.left;
+      private->hint_min_height = rect.bottom - rect.top;
+
+      /* Also check if he current size of the window is in bounds */
+      GetClientRect (private->xwindow, &rect);
+      if (rect.right < geometry->min_width
+         && rect.bottom < geometry->min_height)
+       gdk_window_resize (window, geometry->min_width, geometry->min_height);
+      else if (rect.right < geometry->min_width)
+       gdk_window_resize (window, geometry->min_width, rect.bottom);
+      else if (rect.bottom < geometry->min_height)
+       gdk_window_resize (window, rect.right, geometry->min_height);
+    }
+  
+  if (geom_mask & GDK_HINT_MAX_SIZE)
+    {
+      rect.left = 0;
+      rect.top = 0;
+      rect.right = geometry->max_width;
+      rect.bottom = geometry->max_height;
+      dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+      dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+      AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+      private->hint_max_width = rect.right - rect.left;
+      private->hint_max_height = rect.bottom - rect.top;
+
+      /* Again, check if the window is too large currently. */
+      GetClientRect (private->xwindow, &rect);
+      if (rect.right > geometry->max_width
+         && rect.bottom > geometry->max_height)
+       gdk_window_resize (window, geometry->max_width, geometry->max_height);
+      else if (rect.right > geometry->max_width)
+       gdk_window_resize (window, geometry->max_width, rect.bottom);
+      else if (rect.bottom > geometry->max_height)
+       gdk_window_resize (window, rect.right, geometry->max_height);
+    }
+  
+  /* I don't know what to do when called with zero base_width and height. */
+  if (geom_mask & GDK_HINT_BASE_SIZE
+      && geometry->base_width > 0
+      && geometry->base_height > 0)
+    if (!GetWindowPlacement (private->xwindow, &size_hints))
+      g_warning ("gdk_window_set_hints: GetWindowPlacement failed");
+    else
+      {
+       GDK_NOTE (MISC, g_print ("gdk_window_set_geometry_hints:"
+                                " rcNormalPosition: (%d,%d)--(%d,%d)\n",
+                                size_hints.rcNormalPosition.left,
+                                size_hints.rcNormalPosition.top,
+                                size_hints.rcNormalPosition.right,
+                                size_hints.rcNormalPosition.bottom));
+       size_hints.rcNormalPosition.right =
+         size_hints.rcNormalPosition.left + geometry->base_width;
+       size_hints.rcNormalPosition.bottom =
+         size_hints.rcNormalPosition.top + geometry->base_height;
+       GDK_NOTE (MISC, g_print ("...setting: rcNormal: (%d,%d)--(%d,%d)\n",
+                                size_hints.rcNormalPosition.left,
+                                size_hints.rcNormalPosition.top,
+                                size_hints.rcNormalPosition.right,
+                                size_hints.rcNormalPosition.bottom));
+       if (!SetWindowPlacement (private->xwindow, &size_hints))
+         g_warning ("gdk_window_set_hints: SetWindowPlacement failed");
+      }
+  
+  if (geom_mask & GDK_HINT_RESIZE_INC)
+    {
+      /* XXX */
+    }
+  
+  if (geom_mask & GDK_HINT_ASPECT)
+    {
+      /* XXX */
+    }
+}
+
+void
+gdk_window_set_title (GdkWindow   *window,
+                     const gchar *title)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      if (!SetWindowText (private->xwindow, title))
+       g_warning ("gdk_window_set_title: SetWindowText failed");
+    }
+}
+
+void          
+gdk_window_set_role (GdkWindow   *window,
+                    const gchar *role)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+
+  GDK_NOTE (MISC, g_print ("gdk_window_set_role: %#x %s\n",
+                          private->xwindow, (role ? role : "NULL")));
+  /* XXX */
+}
+
+void          
+gdk_window_set_transient_for (GdkWindow *window, 
+                             GdkWindow *parent)
+{
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *parent_private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  parent_private = (GdkWindowPrivate*) parent;
+
+  GDK_NOTE (MISC, g_print ("gdk_window_set_transient_for: %#x %#x\n",
+                          private->xwindow, parent_private->xwindow));
+  /* XXX */
+}
+
+void
+gdk_window_set_background (GdkWindow *window,
+                          GdkColor  *color)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      GdkColormapPrivate *colormap_private =
+       (GdkColormapPrivate *) private->colormap;
+
+      GDK_NOTE (MISC, g_print ("gdk_window_set_background: %#x %s\n",
+                              private->xwindow, 
+                              gdk_color_to_string (color)));
+
+      if (private->bg_type == GDK_WIN32_BG_PIXMAP)
+       {
+         if (private->bg_pixmap != NULL)
+           {
+             gdk_pixmap_unref (private->bg_pixmap);
+             private->bg_pixmap = NULL;
+           }
+         private->bg_type = GDK_WIN32_BG_NORMAL;
+       }
+#ifdef MULTIPLE_WINDOW_CLASSES
+      if (colormap_private != NULL
+             && colormap_private->xcolormap->rc_palette)
+       {
+         /* If we are on a palettized display we can't use the window
+          * class background brush, but must handle WM_ERASEBKGND.
+          * At least, I think so.
+          */
+#endif
+         private->bg_type = GDK_WIN32_BG_PIXEL;
+         private->bg_pixel = *color;
+#ifdef MULTIPLE_WINDOW_CLASSES
+       }
+      else
+       {
+         /* Non-palettized display; just set the window class background
+            brush. */
+         HBRUSH hbr;
+         HGDIOBJ oldbrush;
+         COLORREF background;
+
+         background = RGB (color->red >> 8,
+                           color->green >> 8,
+                           color->blue >> 8);
+
+         if ((hbr = CreateSolidBrush (GetNearestColor (gdk_DC,
+                                                       background))) == NULL)
+           {
+             g_warning ("gdk_window_set_background: CreateSolidBrush failed");
+             return;
+           }
+
+         oldbrush = (HGDIOBJ) GetClassLong (private->xwindow,
+                                            GCL_HBRBACKGROUND);
+
+         if (SetClassLong (private->xwindow, GCL_HBRBACKGROUND,
+                           (LONG) hbr) == 0)
+           g_warning ("gdk_window_set_background: SetClassLong failed");
+
+         if (!DeleteObject (oldbrush))
+           g_warning ("gdk_window_set_background: DeleteObject failed");
+       }
+#endif
+    }
+}
+
+void
+gdk_window_set_back_pixmap (GdkWindow *window,
+                           GdkPixmap *pixmap,
+                           gint       parent_relative)
+{
+  GdkWindowPrivate *window_private;
+#ifdef MULTIPLE_WINDOW_CLASSES
+  GdkPixmapPrivate *pixmap_private;
+#endif
+
+  g_return_if_fail (window != NULL);
+  
+  window_private = (GdkWindowPrivate*) window;
+#ifdef MULTIPLE_WINDOW_CLASSES
+  pixmap_private = (GdkPixmapPrivate*) pixmap;
+#endif
+
+  if (!window_private->destroyed)
+    {
+      GdkColormapPrivate *colormap_private =
+       (GdkColormapPrivate *) window_private->colormap;
+      if (window_private->bg_type == GDK_WIN32_BG_PIXMAP)
+       {
+         if (window_private->bg_pixmap != NULL)
+           {
+             gdk_pixmap_unref (window_private->bg_pixmap);
+             window_private->bg_pixmap = NULL;
+           }
+         window_private->bg_type = GDK_WIN32_BG_NORMAL;
+       }
+      if (parent_relative)
+       {
+         window_private->bg_type = GDK_WIN32_BG_PARENT_RELATIVE;
+       }
+      else if (!pixmap)
+       {
+#ifdef MULTIPLE_WINDOW_CLASSES
+         SetClassLong (window_private->xwindow, GCL_HBRBACKGROUND,
+                       (LONG) GetStockObject (BLACK_BRUSH));
+#endif
+       }
+#ifdef MULTIPLE_WINDOW_CLASSES
+      else if (colormap_private->xcolormap->rc_palette)
+       {
+         /* Must do the background painting in the
+          * WM_ERASEBKGND handler.
+          */
+         window_private->bg_type = GDK_WIN32_BG_PIXMAP;
+         window_private->bg_pixmap = pixmap;
+         gdk_pixmap_ref (pixmap);
+       }
+      else if (pixmap_private->width <= 8
+              && pixmap_private->height <= 8)
+       {
+         /* We can use small pixmaps directly as background brush */
+         SetClassLong (window_private->xwindow, GCL_HBRBACKGROUND,
+                       (LONG) CreatePatternBrush (pixmap_private->xwindow));
+       }
+#endif
+      else
+       {
+         /* We must cache the pixmap in the WindowPrivate and
+          * paint it each time we get WM_ERASEBKGND
+          */
+         window_private->bg_type = GDK_WIN32_BG_PIXMAP;
+         window_private->bg_pixmap = pixmap;
+         gdk_pixmap_ref (pixmap);
+       }
+    }
+}
+
+void
+gdk_window_set_cursor (GdkWindow *window,
+                      GdkCursor *cursor)
+{
+  GdkWindowPrivate *window_private;
+  GdkCursorPrivate *cursor_private;
+  HCURSOR xcursor;
+  
+  g_return_if_fail (window != NULL);
+  
+  window_private = (GdkWindowPrivate*) window;
+  cursor_private = (GdkCursorPrivate*) cursor;
+  
+  if (!window_private->destroyed)
+    {
+      if (!cursor)
+       xcursor = LoadCursor (NULL, IDC_ARROW);
+      else
+       xcursor = cursor_private->xcursor;
+
+      GDK_NOTE (MISC, g_print ("gdk_window_set_cursor: %#x %#x\n",
+                              window_private->xwindow, xcursor));
+#ifdef MULTIPLE_WINDOW_CLASSES
+      if (!SetClassLong (window_private->xwindow, GCL_HCURSOR, (LONG) xcursor))
+       g_warning ("gdk_window_set_cursor: SetClassLong failed");
+#else
+      window_private->xcursor = xcursor;
+#endif
+      SetCursor (xcursor);
+    }
+}
+
+void
+gdk_window_set_colormap (GdkWindow   *window,
+                        GdkColormap *colormap)
+{
+  GdkWindowPrivate *window_private;
+  GdkColormapPrivate *colormap_private;
+  
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (colormap != NULL);
+  
+  window_private = (GdkWindowPrivate*) window;
+  colormap_private = (GdkColormapPrivate*) colormap;
+  
+  if (!window_private->destroyed)
+    {
+      /* XXX ??? */
+      GDK_NOTE (MISC, g_print ("gdk_window_set_colormap: %#x %#x\n",
+                              window_private->xwindow,
+                              colormap_private->xcolormap));
+      if (window_private->colormap)
+       gdk_colormap_unref (window_private->colormap);
+      window_private->colormap = colormap;
+      gdk_colormap_ref (window_private->colormap);
+      
+      if (window_private->window_type != GDK_WINDOW_TOPLEVEL)
+       gdk_window_add_colormap_windows (window);
+    }
+}
+
+void
+gdk_window_get_user_data (GdkWindow *window,
+                         gpointer  *data)
+{
+  g_return_if_fail (window != NULL);
+  
+  *data = window->user_data;
+}
+
+void
+gdk_window_get_geometry (GdkWindow *window,
+                        gint      *x,
+                        gint      *y,
+                        gint      *width,
+                        gint      *height,
+                        gint      *depth)
+{
+  GdkWindowPrivate *window_private;
+  
+  if (!window)
+    window = (GdkWindow*) &gdk_root_parent;
+  
+  window_private = (GdkWindowPrivate*) window;
+  
+  if (!window_private->destroyed)
+    {
+      RECT rect;
+
+      if (!GetClientRect (window_private->xwindow, &rect))
+       g_warning ("gdk_window_get_geometry: GetClientRect failed");
+
+      if (x)
+       *x = rect.left;
+      if (y)
+       *y = rect.top;
+      if (width)
+       *width = rect.right - rect.left;
+      if (height)
+       *height = rect.bottom - rect.top;
+      if (depth)
+       *depth = gdk_window_get_visual (window)->depth;
+    }
+}
+
+void
+gdk_window_get_position (GdkWindow *window,
+                        gint      *x,
+                        gint      *y)
+{
+  GdkWindowPrivate *window_private;
+  
+  g_return_if_fail (window != NULL);
+  
+  window_private = (GdkWindowPrivate*) window;
+  
+  if (x)
+    *x = window_private->x;
+  if (y)
+    *y = window_private->y;
+}
+
+void
+gdk_window_get_size (GdkWindow *window,
+                    gint       *width,
+                    gint       *height)
+{
+  GdkWindowPrivate *window_private;
+  
+  g_return_if_fail (window != NULL);
+  
+  window_private = (GdkWindowPrivate*) window;
+  
+  if (width)
+    *width = window_private->width;
+  if (height)
+    *height = window_private->height;
+}
+
+GdkVisual*
+gdk_window_get_visual (GdkWindow *window)
+{
+  GdkWindowPrivate *window_private;
+   
+  g_return_val_if_fail (window != NULL, NULL);
+
+  window_private = (GdkWindowPrivate*) window;
+  /* Huh? ->parent is never set for a pixmap. We should just return
+   * null immeditately
+   */
+  while (window_private && (window_private->window_type == GDK_WINDOW_PIXMAP))
+    window_private = (GdkWindowPrivate*) window_private->parent;
+  
+  if (window_private && !window_private->destroyed)
+    {
+       if (window_private->colormap == NULL)
+        {
+           return gdk_visual_get_system (); /* XXX ??? */
+        }
+       else
+        return ((GdkColormapPrivate *)window_private->colormap)->visual;
+    }
+  
+  return NULL;
+}
+
+GdkColormap*
+gdk_window_get_colormap (GdkWindow *window)
+{
+  GdkWindowPrivate *window_private;
+  
+  g_return_val_if_fail (window != NULL, NULL);
+  window_private = (GdkWindowPrivate*) window;
+
+  g_return_val_if_fail (window_private->window_type != GDK_WINDOW_PIXMAP, NULL);
+  if (!window_private->destroyed)
+    {
+      if (window_private->colormap == NULL)
+       {
+         return gdk_colormap_get_system (); /* XXX ??? */
+        }
+       else
+        return window_private->colormap;
+    }
+  
+  return NULL;
+}
+
+GdkWindowType
+gdk_window_get_type (GdkWindow *window)
+{
+  GdkWindowPrivate *window_private;
+
+  g_return_val_if_fail (window != NULL, (GdkWindowType) -1);
+
+  window_private = (GdkWindowPrivate*) window;
+  return window_private->window_type;
+}
+
+gint
+gdk_window_get_origin (GdkWindow *window,
+                      gint      *x,
+                      gint      *y)
+{
+  GdkWindowPrivate *private;
+  gint return_val;
+  gint tx = 0;
+  gint ty = 0;
+
+  g_return_val_if_fail (window != NULL, 0);
+
+  private = (GdkWindowPrivate*) window;
+
+  if (!private->destroyed)
+    {
+      POINT pt;
+
+      pt.x = 0;
+      pt.y = 0;
+      ClientToScreen (private->xwindow, &pt);
+      tx = pt.x;
+      ty = pt.y;
+      return_val = 1;
+    }
+  else
+    return_val = 0;
+  
+  if (x)
+    *x = tx;
+  if (y)
+    *y = ty;
+  
+  return return_val;
+}
+
+gboolean
+gdk_window_get_deskrelative_origin (GdkWindow *window,
+                                   gint      *x,
+                                   gint      *y)
+{
+  return gdk_window_get_origin (window, x, y);
+}
+
+void
+gdk_window_get_root_origin (GdkWindow *window,
+                           gint      *x,
+                           gint      *y)
+{
+  GdkWindowPrivate *private;
+  POINT pt;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (x)
+    *x = 0;
+  if (y)
+    *y = 0;
+  if (private->destroyed)
+    return;
+      
+  while (private->parent && ((GdkWindowPrivate*) private->parent)->parent)
+    private = (GdkWindowPrivate*) private->parent;
+  if (private->destroyed)
+    return;
+
+  pt.x = 0;
+  pt.y = 0;
+  ClientToScreen (private->xwindow, &pt);
+  if (x)
+    *x = pt.x;
+  if (y)
+    *y = pt.y;
+}
+
+GdkWindow*
+gdk_window_get_pointer (GdkWindow       *window,
+                       gint            *x,
+                       gint            *y,
+                       GdkModifierType *mask)
+{
+  GdkWindowPrivate *private;
+  GdkWindow *return_val;
+  POINT pointc, point;
+  HWND hwnd, hwndc;
+
+  if (!window)
+    window = (GdkWindow*) &gdk_root_parent;
+
+  private = (GdkWindowPrivate*) window;
+
+  return_val = NULL;
+  GetCursorPos (&pointc);
+  point = pointc;
+  ScreenToClient (private->xwindow, &point);
+
+  if (x)
+    *x = point.x;
+  if (y)
+    *y = point.y;
+
+  hwnd = WindowFromPoint (point);
+  point = pointc;
+  ScreenToClient (hwnd, &point);
+  
+  do {
+    hwndc = ChildWindowFromPoint (hwnd, point);
+    ClientToScreen (hwnd, &point);
+    ScreenToClient (hwndc, &point);
+  } while (hwndc != hwnd && (hwnd = hwndc, 1));        /* Ouch! */
+
+  return_val = gdk_window_lookup (hwnd);
+
+  if (mask)
+    {
+      BYTE kbd[256];
+
+      GetKeyboardState (kbd);
+      *mask = 0;
+      if (kbd[VK_SHIFT] & 0x80)
+       *mask |= GDK_SHIFT_MASK;
+      if (kbd[VK_CAPITAL] & 0x80)
+       *mask |= GDK_LOCK_MASK;
+      if (kbd[VK_CONTROL] & 0x80)
+       *mask |= GDK_CONTROL_MASK;
+      if (kbd[VK_MENU] & 0x80)
+       *mask |= GDK_MOD1_MASK;
+      if (kbd[VK_LBUTTON] & 0x80)
+       *mask |= GDK_BUTTON1_MASK;
+      if (kbd[VK_MBUTTON] & 0x80)
+       *mask |= GDK_BUTTON2_MASK;
+      if (kbd[VK_RBUTTON] & 0x80)
+       *mask |= GDK_BUTTON3_MASK;
+    }
+  
+  return return_val;
+}
+
+GdkWindow*
+gdk_window_at_pointer (gint *win_x,
+                      gint *win_y)
+{
+  GdkWindowPrivate *private;
+  GdkWindow *window;
+  POINT point, pointc;
+  HWND hwnd, hwndc;
+  RECT rect;
+
+  private = &gdk_root_parent;
+
+  GetCursorPos (&pointc);
+  point = pointc;
+  hwnd = WindowFromPoint (point);
+
+  if (hwnd == NULL)
+    {
+      window = (GdkWindow *) &gdk_root_parent;
+      if (win_x)
+       *win_x = pointc.x;
+      if (win_y)
+       *win_y = pointc.y;
+      return window;
+    }
+      
+  ScreenToClient (hwnd, &point);
+
+  do {
+    hwndc = ChildWindowFromPoint (hwnd, point);
+    ClientToScreen (hwnd, &point);
+    ScreenToClient (hwndc, &point);
+  } while (hwndc != hwnd && (hwnd = hwndc, 1));
+
+  window = gdk_window_lookup (hwnd);
+
+  if (window && (win_x || win_y))
+    {
+      GetClientRect (hwnd, &rect);
+      if (win_x)
+       *win_x = point.x - rect.left;
+      if (win_y)
+       *win_y = point.y - rect.top;
+    }
+
+  GDK_NOTE (MISC, g_print ("gdk_window_at_pointer: +%d+%d %#x%s\n",
+                          point.x, point.y, hwnd,
+                          (window == NULL ? " NULL" : "")));
+
+  return window;
+}
+
+GdkWindow*
+gdk_window_get_parent (GdkWindow *window)
+{
+  g_return_val_if_fail (window != NULL, NULL);
+
+  return ((GdkWindowPrivate*) window)->parent;
+}
+
+GdkWindow*
+gdk_window_get_toplevel (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  private = (GdkWindowPrivate*) window;
+
+  while (private->window_type == GDK_WINDOW_CHILD)
+    {
+      window = ((GdkWindowPrivate*) window)->parent;
+      private = (GdkWindowPrivate*) window;
+    }
+
+  return window;
+}
+
+GList*
+gdk_window_get_children (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+  GList *children;
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return NULL;
+
+  /* XXX ??? */
+  g_warning ("gdk_window_get_children ???");
+  children = NULL;
+
+  return children;
+}
+
+GdkEventMask  
+gdk_window_get_events (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+  GdkEventMask event_mask;
+
+  g_return_val_if_fail (window != NULL, 0);
+
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return 0;
+
+  event_mask = 0;
+
+  event_mask = private->event_mask;
+
+  return event_mask;
+}
+
+void          
+gdk_window_set_events (GdkWindow   *window,
+                      GdkEventMask event_mask)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return;
+
+  private->event_mask = event_mask;
+}
+
+void
+gdk_window_add_colormap_windows (GdkWindow *window)
+{
+  g_warning ("gdk_window_add_colormap_windows not implemented"); /* XXX */
+}
+
+/*
+ * This needs the X11 shape extension.
+ * If not available, shaped windows will look
+ * ugly, but programs still work.    Stefan Wille
+ */
+void
+gdk_window_shape_combine_mask (GdkWindow *window,
+                              GdkBitmap *mask,
+                              gint x, gint y)
+{
+  GdkWindowPrivate *window_private;
+
+  g_return_if_fail (window != NULL);
+
+  window_private = (GdkWindowPrivate*) window;
+  
+  if (!mask)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %#x none\n",
+                              window_private->xwindow));
+      SetWindowRgn (window_private->xwindow, NULL, TRUE);
+    }
+  else
+    {
+      GdkPixmapPrivate *pixmap_private;
+      HRGN hrgn;
+      DWORD dwStyle;
+      DWORD dwExStyle;
+      RECT rect;
+
+      /* Convert mask bitmap to region */
+      pixmap_private = (GdkPixmapPrivate*) mask;
+      hrgn = BitmapToRegion (pixmap_private->xwindow);
+
+      GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %#x %#x\n",
+                              window_private->xwindow,
+                              pixmap_private->xwindow));
+
+      /* SetWindowRgn wants window (not client) coordinates */ 
+      dwStyle = GetWindowLong (window_private->xwindow, GWL_STYLE);
+      dwExStyle = GetWindowLong (window_private->xwindow, GWL_EXSTYLE);
+      GetClientRect (window_private->xwindow, &rect);
+      AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+      OffsetRgn (hrgn, -rect.left, -rect.top);
+
+      OffsetRgn (hrgn, x, y);
+
+      /* If this is a top-level window, add the title bar to the region */
+      if (window_private->window_type == GDK_WINDOW_TOPLEVEL)
+       {
+         CombineRgn (hrgn, hrgn,
+                     CreateRectRgn (0, 0, rect.right - rect.left, -rect.top),
+                     RGN_OR);
+       }
+      
+      SetWindowRgn (window_private->xwindow, hrgn, TRUE);
+    }
+}
+
+void          
+gdk_window_add_filter (GdkWindow     *window,
+                      GdkFilterFunc  function,
+                      gpointer       data)
+{
+  GdkWindowPrivate *private;
+  GList *tmp_list;
+  GdkEventFilter *filter;
+
+  private = (GdkWindowPrivate*) window;
+  if (private && private->destroyed)
+    return;
+
+  if (private)
+    tmp_list = private->filters;
+  else
+    tmp_list = gdk_default_filters;
+
+  while (tmp_list)
+    {
+      filter = (GdkEventFilter *)tmp_list->data;
+      if ((filter->function == function) && (filter->data == data))
+       return;
+      tmp_list = tmp_list->next;
+    }
+
+  filter = g_new (GdkEventFilter, 1);
+  filter->function = function;
+  filter->data = data;
+
+  if (private)
+    private->filters = g_list_append (private->filters, filter);
+  else
+    gdk_default_filters = g_list_append (gdk_default_filters, filter);
+}
+
+void
+gdk_window_remove_filter (GdkWindow     *window,
+                         GdkFilterFunc  function,
+                         gpointer       data)
+{
+  GdkWindowPrivate *private;
+  GList *tmp_list, *node;
+  GdkEventFilter *filter;
+
+  private = (GdkWindowPrivate*) window;
+
+  if(private)
+    tmp_list = private->filters;
+  else
+    tmp_list = gdk_default_filters;
+
+  while (tmp_list)
+    {
+      filter = (GdkEventFilter *)tmp_list->data;
+      node = tmp_list;
+      tmp_list = tmp_list->next;
+
+      if ((filter->function == function) && (filter->data == data))
+       {
+         if(private)
+           private->filters = g_list_remove_link (private->filters, node);
+         else
+           gdk_default_filters = g_list_remove_link (gdk_default_filters, tmp_list);
+         g_list_free_1 (node);
+         g_free (filter);
+         
+         return;
+       }
+    }
+}
+
+void
+gdk_window_set_override_redirect (GdkWindow *window,
+                                 gboolean   override_redirect)
+{
+  g_warning ("gdk_window_set_override_redirect not implemented"); /* XXX */
+}
+
+void          
+gdk_window_set_icon (GdkWindow *window, 
+                    GdkWindow *icon_window,
+                    GdkPixmap *pixmap,
+                    GdkBitmap *mask)
+{
+  g_warning ("gdk_window_set_icon not implemented"); /* XXX */
+}
+
+void          
+gdk_window_set_icon_name (GdkWindow *window, 
+                         gchar     *name)
+{
+  GdkWindowPrivate *window_private;
+
+  g_return_if_fail (window != NULL);
+  window_private = (GdkWindowPrivate*) window;
+  if (window_private->destroyed)
+    return;
+
+  if (!SetWindowText (window_private->xwindow, name))
+    g_warning ("gdk_window_set_icon_name: SetWindowText failed");
+}
+
+void          
+gdk_window_set_group (GdkWindow *window, 
+                     GdkWindow *leader)
+{
+  g_warning ("gdk_window_set_group not implemented"); /* XXX */
+}
+
+void
+gdk_window_set_decorations (GdkWindow      *window,
+                           GdkWMDecoration decorations)
+{
+  GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
+  LONG style, exstyle;
+
+  style = GetWindowLong (window_private->xwindow, GWL_STYLE);
+  exstyle = GetWindowLong (window_private->xwindow, GWL_EXSTYLE);
+
+  style &= (WS_OVERLAPPED|WS_POPUP|WS_CHILD|WS_MINIMIZE|WS_VISIBLE|WS_DISABLED
+           |WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZE);
+
+  exstyle &= (WS_EX_TOPMOST|WS_EX_TRANSPARENT);
+
+  if (decorations & GDK_DECOR_ALL)
+    style |= (WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX);
+  if (decorations & GDK_DECOR_BORDER)
+    style |= (WS_BORDER);
+  if (decorations & GDK_DECOR_RESIZEH)
+    style |= (WS_THICKFRAME);
+  if (decorations & GDK_DECOR_TITLE)
+    style |= (WS_CAPTION);
+  if (decorations & GDK_DECOR_MENU)
+    style |= (WS_SYSMENU);
+  if (decorations & GDK_DECOR_MINIMIZE)
+    style |= (WS_MINIMIZEBOX);
+  if (decorations & GDK_DECOR_MAXIMIZE)
+    style |= (WS_MAXIMIZEBOX);
+  
+  SetWindowLong (window_private->xwindow, GWL_STYLE, style);
+}
+
+void
+gdk_window_set_functions (GdkWindow    *window,
+                         GdkWMFunction functions)
+{
+  GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
+  LONG style, exstyle;
+
+  style = GetWindowLong (window_private->xwindow, GWL_STYLE);
+  exstyle = GetWindowLong (window_private->xwindow, GWL_EXSTYLE);
+
+  style &= (WS_OVERLAPPED|WS_POPUP|WS_CHILD|WS_MINIMIZE|WS_VISIBLE|WS_DISABLED
+           |WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZE|WS_CAPTION|WS_BORDER
+           |WS_SYSMENU);
+
+  exstyle &= (WS_EX_TOPMOST|WS_EX_TRANSPARENT);
+
+  if (functions & GDK_FUNC_ALL)
+    style |= (WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX);
+  if (functions & GDK_FUNC_RESIZE)
+    style |= (WS_THICKFRAME);
+  if (functions & GDK_FUNC_MOVE)
+    style |= (WS_THICKFRAME);
+  if (functions & GDK_FUNC_MINIMIZE)
+    style |= (WS_MINIMIZEBOX);
+  if (functions & GDK_FUNC_MAXIMIZE)
+    style |= (WS_MAXIMIZEBOX);
+  
+  SetWindowLong (window_private->xwindow, GWL_STYLE, style);
+}
+
+GList *
+gdk_window_get_toplevels (void)
+{
+  GList *new_list = NULL;
+  GList *tmp_list;
+
+  tmp_list = gdk_root_parent.children;
+  while (tmp_list)
+    {
+      new_list = g_list_prepend (new_list, tmp_list->data);
+      tmp_list = tmp_list->next;
+    }
+
+  return new_list;
+}
+
+/* 
+ * propagate the shapes from all child windows of a GDK window to the parent 
+ * window. Shamelessly ripped from Enlightenment's code
+ * 
+ * - Raster
+ */
+
+static void
+QueryTree (HWND hwnd,
+          HWND **children,
+          gint *nchildren)
+{
+  guint i, n;
+  HWND child;
+
+  n = 0;
+  do {
+    if (n == 0)
+      child = GetWindow (hwnd, GW_CHILD);
+    else
+      child = GetWindow (child, GW_HWNDNEXT);
+    if (child != NULL)
+      n++;
+  } while (child != NULL);
+
+  if (n > 0)
+    {
+      *children = g_new (HWND, n);
+      for (i = 0; i < n; i++)
+       {
+         if (i == 0)
+           child = GetWindow (hwnd, GW_CHILD);
+         else
+           child = GetWindow (child, GW_HWNDNEXT);
+         *children[i] = child;
+       }
+    }
+}
+
+static void
+gdk_propagate_shapes (HANDLE   win,
+                     gboolean merge)
+{
+   RECT emptyRect;
+   HRGN region, childRegion;
+   RECT rect;
+   HWND *list = NULL;
+   gint i, num;
+
+   SetRectEmpty (&emptyRect);
+   region = CreateRectRgnIndirect (&emptyRect);
+   if (merge)
+     GetWindowRgn (win, region);
+   
+   QueryTree (win, &list, &num);
+   if (list != NULL)
+     {
+       WINDOWPLACEMENT placement;
+
+       placement.length = sizeof (WINDOWPLACEMENT);
+       /* go through all child windows and create/insert spans */
+       for (i = 0; i < num; i++)
+        {
+          GetWindowPlacement (list[i], &placement);
+          if (placement.showCmd = SW_SHOWNORMAL)
+            {
+              childRegion = CreateRectRgnIndirect (&emptyRect);
+              GetWindowRgn (list[i], childRegion);
+              CombineRgn (region, region, childRegion, RGN_OR);
+            }
+         }
+       SetWindowRgn (win, region, TRUE);
+     }
+}
+
+void
+gdk_window_set_child_shapes (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+   
+  g_return_if_fail (window != NULL);
+   
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return;
+
+  gdk_propagate_shapes ( private->xwindow, FALSE);
+}
+
+void
+gdk_window_merge_child_shapes (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return;
+
+  gdk_propagate_shapes (private->xwindow, TRUE);
+}
+
+/*************************************************************
+ * gdk_window_is_visible:
+ *     Check if the given window is mapped.
+ *   arguments:
+ *     window: 
+ *   results:
+ *     is the window mapped
+ *************************************************************/
+
+gboolean 
+gdk_window_is_visible (GdkWindow *window)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+
+  g_return_val_if_fail (window != NULL, FALSE);
+
+  return private->mapped;
+}
+
+/*************************************************************
+ * gdk_window_is_viewable:
+ *     Check if the window and all ancestors of the window
+ *     are mapped. (This is not necessarily "viewable" in
+ *     the X sense, since we only check as far as we have
+ *     GDK window parents, not to the root window)
+ *   arguments:
+ *     window:
+ *   results:
+ *     is the window viewable
+ *************************************************************/
+
+gboolean 
+gdk_window_is_viewable (GdkWindow *window)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+
+  g_return_val_if_fail (window != NULL, FALSE);
+
+  while (private && 
+        (private != &gdk_root_parent) &&
+        (private->window_type != GDK_WINDOW_FOREIGN))
+    {
+      if (!private->mapped)
+       return FALSE;
+
+      private = (GdkWindowPrivate *)private->parent;
+    }
+
+  return TRUE;
+}
+
+void          
+gdk_drawable_set_data (GdkDrawable   *drawable,
+                      const gchar   *key,
+                      gpointer       data,
+                      GDestroyNotify destroy_func)
+{
+  g_dataset_set_data_full (drawable, key, data, destroy_func);
+}
+
+
+/* Support for windows that can be guffaw-scrolled
+ * (See http://www.gtk.org/~otaylor/whitepapers/guffaw-scrolling.txt)
+ */
+
+static gboolean
+gdk_window_gravity_works (void)
+{
+  enum { UNKNOWN, NO, YES };
+  static gint gravity_works = UNKNOWN;
+
+  if (gravity_works == UNKNOWN)
+    {
+      GdkWindowAttr attr;
+      GdkWindow *parent;
+      GdkWindow *child;
+      gint y;
+      
+      attr.window_type = GDK_WINDOW_TEMP;
+      attr.wclass = GDK_INPUT_OUTPUT;
+      attr.x = 0;
+      attr.y = 0;
+      attr.width = 100;
+      attr.height = 100;
+      attr.event_mask = 0;
+      
+      parent = gdk_window_new (NULL, &attr, GDK_WA_X | GDK_WA_Y);
+      
+      attr.window_type = GDK_WINDOW_CHILD;
+      child = gdk_window_new (parent, &attr, GDK_WA_X | GDK_WA_Y);
+
+      gdk_window_set_static_win_gravity (child, TRUE);
+      
+      gdk_window_resize (parent, 100, 110);
+      gdk_window_move (parent, 0, -10);
+      gdk_window_move_resize (parent, 0, 0, 100, 100);
+      
+      gdk_window_resize (parent, 100, 110);
+      gdk_window_move (parent, 0, -10);
+      gdk_window_move_resize (parent, 0, 0, 100, 100);
+      
+      gdk_window_get_geometry (child, NULL, &y, NULL, NULL, NULL);
+      
+      gdk_window_destroy (parent);
+      gdk_window_destroy (child);
+  
+      gravity_works = ((y == -20) ? YES : NO);
+    }
+
+  return (gravity_works == YES);
+}
+
+static void
+gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+
+  g_return_if_fail (window != NULL);
+
+  GDK_NOTE (MISC,
+           g_print ("gdk_window_set_static_bit_gravity: Not implemented\n"));
+}
+
+static void
+gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+
+  g_return_if_fail (window != NULL);
+
+  GDK_NOTE (MISC,
+           g_print ("gdk_window_set_static_win_gravity: Not implemented\n"));
+}
+
+/*************************************************************
+ * gdk_window_set_static_gravities:
+ *     Set the bit gravity of the given window to static,
+ *     and flag it so all children get static subwindow
+ *     gravity.
+ *   arguments:
+ *     window: window for which to set static gravity
+ *     use_static: Whether to turn static gravity on or off.
+ *   results:
+ *     Does the XServer support static gravity?
+ *************************************************************/
+
+gboolean 
+gdk_window_set_static_gravities (GdkWindow *window,
+                                gboolean   use_static)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+  GList *tmp_list;
+
+  g_return_val_if_fail (window != NULL, FALSE);
+  
+  if (!use_static == !private->guffaw_gravity)
+    return TRUE;
+  
+  if (use_static && !gdk_window_gravity_works ())
+    return FALSE;
+
+  private->guffaw_gravity = use_static;
+
+  gdk_window_set_static_bit_gravity (window, use_static);
+
+  tmp_list = private->children;
+  while (tmp_list)
+    {
+      gdk_window_set_static_win_gravity (window, use_static);
+      
+      tmp_list = tmp_list->next;
+    }
+
+  return TRUE;
+}
diff --git a/gdk/win32/gdkwindow.c b/gdk/win32/gdkwindow.c
new file mode 100644 (file)
index 0000000..02bbace
--- /dev/null
@@ -0,0 +1,2560 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-1999 Tor Lillqvist
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include "gdkinput.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+/* The Win API function AdjustWindowRect may return negative values
+ * resulting in obscured title bars. This helper function is coreccting it.
+ */
+BOOL AdjustWindowRectEx2(RECT* lpRect, 
+                         DWORD dwStyle, 
+                         BOOL bMenu, 
+                         DWORD dwExStyle)
+{
+  if (!AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle))
+    return FALSE;
+  if (lpRect->left < 0)
+    {
+      lpRect->right -= lpRect->left;
+      lpRect->left = 0;
+    }
+  if (lpRect->top < 0)
+    {
+      lpRect->bottom -= lpRect->top;
+      lpRect->top = 0;
+    }
+  return TRUE;
+}
+/* HB: now use it */
+#define AdjustWindowRectEx AdjustWindowRectEx2
+
+/* Forward declarations */
+static gboolean gdk_window_gravity_works (void);
+static void     gdk_window_set_static_win_gravity (GdkWindow *window, 
+                                                  gboolean   on);
+
+/* 
+ * The following fucntion by The Rasterman <raster@redhat.com>
+ * This function returns the X Window ID in which the x y location is in 
+ * (x and y being relative to the root window), excluding any windows listed
+ * in the GList excludes (this is a list of X Window ID's - gpointer being
+ * the Window ID).
+ * 
+ * This is primarily designed for internal gdk use - for DND for example
+ * when using a shaped icon window as the drag object - you exclude the
+ * X Window ID of the "icon" (perhaps more if excludes may be needed) and
+ * You can get back an X Window ID as to what X Window ID is infact under
+ * those X,Y co-ordinates.
+ */
+HWND
+gdk_window_xid_at_coords (gint     x,
+                         gint     y,
+                         GList   *excludes,
+                         gboolean excl_child)
+{
+  POINT pt;
+  gboolean warned = FALSE;
+
+  pt.x = x;
+  pt.y = y;
+  /* This is probably not correct, just a quick hack */
+
+  if (!warned)
+    {
+      g_warning ("gdk_window_xid_at_coords probably not implemented correctly");
+      warned = TRUE;
+    }
+
+  /* XXX */
+  return WindowFromPoint (pt);
+}
+
+void
+gdk_window_init (void)
+{
+  unsigned int width;
+  unsigned int height;
+#if 0
+  width = GetSystemMetrics (SM_CXSCREEN);
+  height = GetSystemMetrics (SM_CYSCREEN);
+#else
+  { RECT r; /* //HB: don't obscure tray window (task bar) */
+    SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
+    width  = r.right - r.left;
+    height = r.bottom - r.top;
+  }
+#endif
+
+  gdk_root_parent.xwindow = gdk_root_window;
+  gdk_root_parent.window_type = GDK_WINDOW_ROOT;
+  gdk_root_parent.window.user_data = NULL;
+  gdk_root_parent.width = width;
+  gdk_root_parent.height = height;
+  gdk_root_parent.children = NULL;
+  gdk_root_parent.colormap = NULL;
+  gdk_root_parent.ref_count = 1;
+
+  gdk_xid_table_insert (&gdk_root_window, &gdk_root_parent);
+}
+
+GdkWindow*
+gdk_window_new (GdkWindow     *parent,
+               GdkWindowAttr *attributes,
+               gint           attributes_mask)
+{
+  GdkWindow *window;
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *parent_private;
+  GdkVisual *visual;
+  HANDLE xparent;
+  Visual *xvisual;
+#ifdef MULTIPLE_WINDOW_CLASSES
+  WNDCLASSEX wcl; 
+  ATOM klass;
+  char wcl_name_buf[20];
+  static int wcl_cnt = 0;
+#else
+  static WNDCLASSEX wcl; 
+  static ATOM klass = 0;
+#endif
+  static HICON hAppIcon = NULL;
+  DWORD dwStyle, dwExStyle;
+  RECT rect;
+  int width, height;
+  int x, y;
+  char *title;
+
+  g_return_val_if_fail (attributes != NULL, NULL);
+
+  if (!parent)
+    parent = (GdkWindow*) &gdk_root_parent;
+
+  parent_private = (GdkWindowPrivate*) parent;
+  if (parent_private->destroyed)
+    return NULL;
+
+  xparent = parent_private->xwindow;
+
+  private = g_new (GdkWindowPrivate, 1);
+  window = (GdkWindow*) private;
+
+  private->parent = parent;
+
+  private->destroyed = FALSE;
+  private->mapped = FALSE;
+  private->guffaw_gravity = FALSE;
+  private->resize_count = 0;
+  private->ref_count = 1;
+
+  if (attributes_mask & GDK_WA_X)
+    x = attributes->x;
+  else
+    x = 0;
+
+  if (attributes_mask & GDK_WA_Y)
+    y = attributes->y;
+  else
+    y = 0;
+
+  private->x = x;
+  private->y = y;
+  private->width = (attributes->width > 1) ? (attributes->width) : (1);
+  private->height = (attributes->height > 1) ? (attributes->height) : (1);
+  private->window_type = attributes->window_type;
+  private->extension_events = 0;
+  private->extension_events_selected = FALSE;
+
+  private->filters = NULL;
+  private->children = NULL;
+
+  window->user_data = NULL;
+
+  if (attributes_mask & GDK_WA_VISUAL)
+    visual = attributes->visual;
+  else
+    visual = gdk_visual_get_system ();
+  xvisual = ((GdkVisualPrivate*) visual)->xvisual;
+
+  if (attributes_mask & GDK_WA_TITLE)
+    title = attributes->title;
+  else
+    title = g_get_prgname ();
+
+  private->event_mask = GDK_STRUCTURE_MASK | attributes->event_mask;
+  private->bg_type = GDK_WIN32_BG_NORMAL;
+  private->hint_flags = 0;
+  
+#ifndef MULTIPLE_WINDOW_CLASSES
+  if (klass == 0)
+    {
+#endif
+  wcl.cbSize = sizeof (WNDCLASSEX);
+#if 1
+  wcl.style = CS_HREDRAW | CS_VREDRAW;
+#else
+  wcl.style = 0;
+#endif
+  wcl.lpfnWndProc = gdk_WindowProc;
+  wcl.cbClsExtra = 0;
+  wcl.cbWndExtra = 0;
+  wcl.hInstance = gdk_ProgInstance;
+  wcl.hCursor = LoadCursor (NULL, IDC_ARROW);
+
+#if 0 /* tml: orig -> generates SetClassLong errors in set background */
+  wcl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
+  wcl.hbrBackground = NULL;
+#else
+  /* initialize once! */
+  if (0 == hAppIcon)
+    {
+      gchar sLoc [_MAX_PATH+1];
+      HINSTANCE hInst = GetModuleHandle(NULL);
+
+      if (0 != GetModuleFileName(hInst, sLoc, _MAX_PATH))
+       {
+         hAppIcon = ExtractIcon(hInst, sLoc, 0);
+         if (0 == hAppIcon)
+           {
+             char *gdklibname = g_strdup_printf ("gdk-%s.dll", GDK_VERSION);
+
+             hAppIcon = ExtractIcon(hInst, gdklibname, 0);
+             g_free (gdklibname);
+           }
+         
+         if (0 == hAppIcon) 
+           hAppIcon = LoadIcon (NULL, IDI_APPLICATION);
+       }
+    }
+  wcl.hIcon = CopyIcon (hAppIcon);
+  wcl.hIconSm = CopyIcon (hAppIcon);
+  /* HB: starting with black to have something to release ... */
+  wcl.hbrBackground = CreateSolidBrush( RGB(0,0,0));
+#endif
+
+  wcl.lpszMenuName = NULL;
+#ifdef MULTIPLE_WINDOW_CLASSES
+  sprintf (wcl_name_buf, "gdk-wcl-%d", wcl_cnt++);
+  wcl.lpszClassName = g_strdup (wcl_name_buf);
+  /* wcl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); */
+#else
+  wcl.lpszClassName = "GDK-window-class";
+  klass = RegisterClassEx (&wcl);
+  if (!klass)
+    g_error ("RegisterClassEx failed");
+    }
+
+  private->xcursor = NULL;
+#endif
+      
+  if (parent_private && parent_private->guffaw_gravity)
+    {
+      /* XXX ??? */
+    }
+
+  if (attributes->wclass == GDK_INPUT_OUTPUT)
+    {
+      dwExStyle = 0;
+      if (attributes_mask & GDK_WA_COLORMAP)
+       private->colormap = attributes->colormap;
+      else
+       private->colormap = gdk_colormap_get_system ();
+    }
+  else
+    {
+      dwExStyle = WS_EX_TRANSPARENT;
+      private->colormap = NULL;
+      private->bg_type = GDK_WIN32_BG_TRANSPARENT;
+      private->bg_pixmap = NULL;
+    }
+
+  if (attributes_mask & GDK_WA_X)
+    x = attributes->x;
+  else
+    x = CW_USEDEFAULT;
+
+  if (attributes_mask & GDK_WA_Y)
+    y = attributes->y;
+  else if (attributes_mask & GDK_WA_X)
+    y = 100;                   /* ??? We must put it somewhere... */
+  else
+    y = 500;                   /* x is CW_USEDEFAULT, y doesn't matter then */
+
+  if (parent_private)
+    parent_private->children = g_list_prepend (parent_private->children, window);
+
+  switch (private->window_type)
+    {
+    case GDK_WINDOW_TOPLEVEL:
+      dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
+      xparent = gdk_root_window;
+      break;
+    case GDK_WINDOW_CHILD:
+      dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+      break;
+    case GDK_WINDOW_DIALOG:
+      dwStyle = WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN;
+      xparent = gdk_root_window;
+      break;
+    case GDK_WINDOW_TEMP:
+      dwStyle = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+#ifdef MULTIPLE_WINDOW_CLASSES
+      wcl.style |= CS_SAVEBITS;
+#endif
+      dwExStyle |= WS_EX_TOOLWINDOW;
+      break;
+    case GDK_WINDOW_ROOT:
+      g_error ("cannot make windows of type GDK_WINDOW_ROOT");
+      break;
+    case GDK_WINDOW_PIXMAP:
+      g_error ("cannot make windows of type GDK_WINDOW_PIXMAP (use gdk_pixmap_new)");
+      break;
+    }
+
+#ifdef MULTIPLE_WINDOW_CLASSES
+  klass = RegisterClassEx (&wcl);
+  if (!klass)
+    g_error ("RegisterClassEx failed");
+#endif
+
+  if (private->window_type != GDK_WINDOW_CHILD)
+    {
+      if (x == CW_USEDEFAULT)
+       {
+         rect.left = 100;
+         rect.top = 100;
+       }
+      else
+       {
+         rect.left = x;
+         rect.top = y;
+       }
+
+      rect.right = rect.left + private->width;
+      rect.bottom = rect.top + private->height;
+
+      if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle))
+       g_warning ("gdk_window_new: AdjustWindowRectEx failed");
+
+      if (x != CW_USEDEFAULT)
+       {
+         x = rect.left;
+         y = rect.top;
+       }
+      width = rect.right - rect.left;
+      height = rect.bottom - rect.top;
+    }
+  else
+    {
+      width = private->width;
+      height = private->height;
+    }
+
+  private->xwindow =
+    CreateWindowEx (dwExStyle,
+                   wcl.lpszClassName,
+                   title,
+                   dwStyle,
+                   x, y, 
+                   width, height,
+                   xparent,
+                   NULL,
+                   gdk_ProgInstance,
+                   NULL);
+  GDK_NOTE (MISC,
+           g_print ("gdk_window_create: %s %s %#x %dx%d@+%d+%d %#x = %#x\n",
+                    (private->window_type == GDK_WINDOW_TOPLEVEL ? "TOPLEVEL" :
+                     (private->window_type == GDK_WINDOW_CHILD ? "CHILD" :
+                      (private->window_type == GDK_WINDOW_DIALOG ? "DIALOG" :
+                       (private->window_type == GDK_WINDOW_TEMP ? "TEMP" :
+                        "???")))),
+                    title,
+                    dwStyle,
+                    width, height, (x == CW_USEDEFAULT ? -9999 : x), y, 
+                    xparent,
+                    private->xwindow));
+
+  gdk_window_ref (window);
+  gdk_xid_table_insert (&private->xwindow, window);
+
+  if (private->colormap)
+    gdk_colormap_ref (private->colormap);
+
+  gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ?
+                                 (attributes->cursor) :
+                                 NULL));
+
+  return window;
+}
+
+GdkWindow *
+gdk_window_foreign_new (guint32 anid)
+{
+  GdkWindow *window;
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *parent_private;
+  HANDLE parent;
+  RECT rect;
+  POINT point;
+
+  private = g_new (GdkWindowPrivate, 1);
+  window = (GdkWindow*) private;
+
+  parent = GetParent ((HWND) anid);
+  private->parent = gdk_xid_table_lookup (parent);
+
+  parent_private = (GdkWindowPrivate *)private->parent;
+  
+  if (parent_private)
+    parent_private->children = g_list_prepend (parent_private->children, window);
+
+  private->xwindow = (HWND) anid;
+  GetClientRect ((HWND) anid, &rect);
+  point.x = rect.left;
+  point.y = rect.right;
+  ClientToScreen ((HWND) anid, &point);
+  if (parent != HWND_DESKTOP)
+    ScreenToClient (parent, &point);
+  private->x = point.x;
+  private->y = point.y;
+  private->width = rect.right - rect.left;
+  private->height = rect.bottom - rect.top;
+  private->resize_count = 0;
+  private->ref_count = 1;
+  private->window_type = GDK_WINDOW_FOREIGN;
+  private->destroyed = FALSE;
+  private->mapped = IsWindowVisible (private->xwindow);
+  private->guffaw_gravity = FALSE;
+  private->extension_events = 0;
+  private->extension_events_selected = FALSE;
+
+  private->colormap = NULL;
+
+  private->filters = NULL;
+  private->children = NULL;
+
+  window->user_data = NULL;
+
+  gdk_window_ref (window);
+  gdk_xid_table_insert (&private->xwindow, window);
+
+  return window;
+}
+
+/* Call this function when you want a window and all its children to
+ * disappear.  When xdestroy is true, a request to destroy the XWindow
+ * is sent out.  When it is false, it is assumed that the XWindow has
+ * been or will be destroyed by destroying some ancestor of this
+ * window.
+ */
+static void
+gdk_window_internal_destroy (GdkWindow *window,
+                            gboolean   xdestroy,
+                            gboolean   our_destroy)
+{
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *temp_private;
+  GdkWindow *temp_window;
+  GList *children;
+  GList *tmp;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+
+  GDK_NOTE (MISC, g_print ("gdk_window_internal_destroy %#x\n",
+                          private->xwindow));
+
+  switch (private->window_type)
+    {
+    case GDK_WINDOW_TOPLEVEL:
+    case GDK_WINDOW_CHILD:
+    case GDK_WINDOW_DIALOG:
+    case GDK_WINDOW_TEMP:
+    case GDK_WINDOW_FOREIGN:
+      if (!private->destroyed)
+       {
+         if (private->parent)
+           {
+             GdkWindowPrivate *parent_private = (GdkWindowPrivate *)private->parent;
+             if (parent_private->children)
+               parent_private->children = g_list_remove (parent_private->children, window);
+           }
+
+         if (private->window_type != GDK_WINDOW_FOREIGN)
+           {
+             children = tmp = private->children;
+             private->children = NULL;
+
+             while (tmp)
+               {
+                 temp_window = tmp->data;
+                 tmp = tmp->next;
+                 
+                 temp_private = (GdkWindowPrivate*) temp_window;
+                 if (temp_private)
+                   gdk_window_internal_destroy (temp_window, FALSE,
+                                                our_destroy);
+               }
+
+             g_list_free (children);
+           }
+
+         if (private->extension_events != 0)
+           gdk_input_window_destroy (window);
+
+         if (private->filters)
+           {
+             tmp = private->filters;
+
+             while (tmp)
+               {
+                 g_free (tmp->data);
+                 tmp = tmp->next;
+               }
+
+             g_list_free (private->filters);
+             private->filters = NULL;
+           }
+         
+         if (private->window_type == GDK_WINDOW_FOREIGN)
+           {
+             if (our_destroy && (private->parent != NULL))
+               {
+                 /* It's somebody elses window, but in our hierarchy,
+                  * so reparent it to the root window, and then send
+                  * it a delete event, as if we were a WM
+                  */
+                 gdk_window_hide (window);
+                 gdk_window_reparent (window, NULL, 0, 0);
+                 
+                 /* Is this too drastic? Many (most?) applications
+                  * quit if any window receives WM_QUIT I think.
+                  * OTOH, I don't think foreign windows are much
+                  * used, so the question is maybe academic.
+                  */
+                 PostMessage (private->xwindow, WM_QUIT, 0, 0);
+               }
+           }
+         else if (xdestroy)
+           DestroyWindow (private->xwindow);
+
+         if (private->colormap)
+           gdk_colormap_unref (private->colormap);
+
+         private->mapped = FALSE;
+         private->destroyed = TRUE;
+       }
+      break;
+
+    case GDK_WINDOW_ROOT:
+      g_error ("attempted to destroy root window");
+      break;
+
+    case GDK_WINDOW_PIXMAP:
+      g_error ("called gdk_window_destroy on a pixmap (use gdk_pixmap_unref)");
+      break;
+    }
+}
+
+/* Like internal_destroy, but also destroys the reference created by
+   gdk_window_new. */
+
+void
+gdk_window_destroy (GdkWindow *window)
+{
+  gdk_window_internal_destroy (window, TRUE, TRUE);
+  gdk_window_unref (window);
+}
+
+/* This function is called when the XWindow is really gone.  */
+
+void
+gdk_window_destroy_notify (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+
+  GDK_NOTE (EVENTS, g_print ("gdk_window_destroy_notify: %#x  %d\n",
+                            private->xwindow, private->destroyed));
+
+  if (!private->destroyed)
+    {
+      if (private->window_type == GDK_WINDOW_FOREIGN)
+       gdk_window_internal_destroy (window, FALSE, FALSE);
+      else
+       g_warning ("GdkWindow %#lx unexpectedly destroyed", private->xwindow);
+    }
+  
+  gdk_xid_table_remove (private->xwindow);
+  gdk_window_unref (window);
+}
+
+GdkWindow*
+gdk_window_ref (GdkWindow *window)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+  g_return_val_if_fail (window != NULL, NULL);
+
+  private->ref_count += 1;
+
+  GDK_NOTE (MISC, g_print ("gdk_window_ref %#x %d\n",
+                          private->xwindow, private->ref_count));
+
+  return window;
+}
+
+void
+gdk_window_unref (GdkWindow *window)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+  g_return_if_fail (window != NULL);
+
+  private->ref_count -= 1;
+
+  GDK_NOTE (MISC, g_print ("gdk_window_unref %#x %d%s\n",
+                          private->xwindow, private->ref_count,
+                          (private->ref_count == 0 ? " freeing" : "")));
+
+  if (private->ref_count == 0)
+    {
+      if (private->bg_type == GDK_WIN32_BG_PIXMAP && private->bg_pixmap != NULL)
+       gdk_pixmap_unref (private->bg_pixmap);
+
+      if (!private->destroyed)
+       {
+         if (private->window_type == GDK_WINDOW_FOREIGN)
+           gdk_xid_table_remove (private->xwindow);
+         else
+           g_warning ("losing last reference to undestroyed window");
+       }
+      g_dataset_destroy (window);
+      g_free (window);
+    }
+}
+
+void
+gdk_window_show (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_show: %#x\n", private->xwindow));
+
+      private->mapped = TRUE;
+      if (private->window_type == GDK_WINDOW_TEMP)
+       {
+         ShowWindow (private->xwindow, SW_SHOWNOACTIVATE);
+         SetWindowPos (private->xwindow, HWND_TOPMOST, 0, 0, 0, 0,
+                       SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+#if 0
+         ShowWindow (private->xwindow, SW_HIDE); /* Don't put on toolbar */
+#endif
+       }
+      else
+       {
+         ShowWindow (private->xwindow, SW_SHOWNORMAL);
+         ShowWindow (private->xwindow, SW_RESTORE);
+         SetForegroundWindow (private->xwindow);
+#if 0
+         ShowOwnedPopups (private->xwindow, TRUE);
+#endif
+       }
+    }
+}
+
+void
+gdk_window_hide (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_hide: %#x\n", private->xwindow));
+
+      private->mapped = FALSE;
+      if (private->window_type == GDK_WINDOW_TOPLEVEL)
+       ShowOwnedPopups (private->xwindow, FALSE);
+#if 1
+      ShowWindow (private->xwindow, SW_HIDE);
+#elif 0
+      ShowWindow (private->xwindow, SW_MINIMIZE);
+#else
+      CloseWindow (private->xwindow);
+#endif
+    }
+}
+
+void
+gdk_window_withdraw (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_withdraw: %#x\n", private->xwindow));
+
+      gdk_window_hide (window);        /* XXX */
+    }
+}
+
+void
+gdk_window_move (GdkWindow *window,
+                gint       x,
+                gint       y)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      RECT rect;
+      DWORD dwStyle;
+      DWORD dwExStyle;
+
+      GDK_NOTE (MISC, g_print ("gdk_window_move: %#x +%d+%d\n",
+                              private->xwindow, x, y));
+      GetClientRect (private->xwindow, &rect);
+
+      dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+      dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+      if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle))
+       g_warning ("gdk_window_move: AdjustWindowRectEx failed");
+      if (private->window_type == GDK_WINDOW_CHILD)
+       {
+         private->x = x;
+         private->y = y;
+       }
+      GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n",
+                              private->xwindow,
+                              rect.right - rect.left, rect.bottom - rect.top,
+                              x + rect.left, y + rect.top));
+      if (!MoveWindow (private->xwindow,
+                      x + rect.left, y + rect.top,
+                      rect.right - rect.left, rect.bottom - rect.top,
+                      TRUE))
+       g_warning ("gdk_window_move: MoveWindow failed");
+    }
+}
+
+void
+gdk_window_resize (GdkWindow *window,
+                  gint       width,
+                  gint       height)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  if ((gint16) width < 1)
+    width = 1;
+  if ((gint16) height < 1)
+    height = 1;
+
+  private = (GdkWindowPrivate*) window;
+
+  if (!private->destroyed &&
+      ((private->resize_count > 0) ||
+       (private->width != (guint16) width) ||
+       (private->height != (guint16) height)))
+    {
+      RECT rect;
+      POINT pt;
+      DWORD dwStyle;
+      DWORD dwExStyle;
+      int x, y;
+
+      GDK_NOTE (MISC, g_print ("gdk_window_resize: %#x %dx%d\n",
+                              private->xwindow, width, height));
+      
+      pt.x = 0;
+      pt.y = 0; 
+      ClientToScreen (private->xwindow, &pt);
+      rect.left = pt.x;
+      rect.top = pt.y;
+      rect.right = pt.x + width;
+      rect.bottom = pt.y + height;
+
+      dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+      dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+      if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle))
+       g_warning ("gdk_window_resize: AdjustWindowRectEx failed");
+      if (private->window_type != GDK_WINDOW_CHILD)
+       {
+         x = rect.left;
+         y = rect.top;
+       }
+      else
+       {
+         x = private->x;
+         y = private->y;
+       }
+
+      private->resize_count += 1;
+
+      if (private->window_type == GDK_WINDOW_CHILD)
+       {
+         private->width = width;
+         private->height = height;
+       }
+      GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n",
+                              private->xwindow,
+                              rect.right - rect.left, rect.bottom - rect.top,
+                              x, y));
+      if (!MoveWindow (private->xwindow,
+                      x, y,
+                      rect.right - rect.left, rect.bottom - rect.top,
+                      TRUE))
+       g_warning ("gdk_window_resize: MoveWindow failed");
+    }
+}
+
+void
+gdk_window_move_resize (GdkWindow *window,
+                       gint       x,
+                       gint       y,
+                       gint       width,
+                       gint       height)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  if ((gint16) width < 1)
+    width = 1;
+  if ((gint16) height < 1)
+    height = 1;
+
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      RECT rect;
+      DWORD dwStyle;
+      DWORD dwExStyle;
+
+      GDK_NOTE (MISC, g_print ("gdk_window_move_resize: %#x %dx%d@+%d+%d\n",
+                              private->xwindow, width, height, x, y));
+      
+      rect.left = x;
+      rect.top = y;
+      rect.right = x + width;
+      rect.bottom = y + height;
+
+      dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+      dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+      if (!AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle))
+       g_warning ("gdk_window_move_resize: AdjustWindowRectEx failed");
+
+      if (private->window_type == GDK_WINDOW_CHILD)
+       {
+         private->x = x;
+         private->y = y;
+         private->width = width;
+         private->height = height;
+       }
+      GDK_NOTE (MISC, g_print ("...MoveWindow(%#x,%dx%d@+%d+%d)\n",
+                              private->xwindow,
+                              rect.right - rect.left, rect.bottom - rect.top,
+                              rect.left, rect.top));
+      if (!MoveWindow (private->xwindow,
+                      rect.left, rect.top,
+                      rect.right - rect.left, rect.bottom - rect.top,
+                      TRUE))
+       g_warning ("gdk_window_move_resize: MoveWindow failed");
+
+      if (private->guffaw_gravity)
+       {
+         GList *tmp_list = private->children;
+         while (tmp_list)
+           {
+             GdkWindowPrivate *child_private = tmp_list->data;
+             
+             child_private->x -= x - private->x;
+             child_private->y -= y - private->y;
+             
+             tmp_list = tmp_list->next;
+           }
+       }
+      
+    }
+}
+
+void
+gdk_window_reparent (GdkWindow *window,
+                    GdkWindow *new_parent,
+                    gint       x,
+                    gint       y)
+{
+  GdkWindowPrivate *window_private;
+  GdkWindowPrivate *parent_private;
+  GdkWindowPrivate *old_parent_private;
+
+  g_return_if_fail (window != NULL);
+
+  if (!new_parent)
+    new_parent = (GdkWindow*) &gdk_root_parent;
+
+  window_private = (GdkWindowPrivate*) window;
+  old_parent_private = (GdkWindowPrivate*)window_private->parent;
+  parent_private = (GdkWindowPrivate*) new_parent;
+
+  if (!window_private->destroyed && !parent_private->destroyed)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_reparent: %#x %#x\n",
+                              window_private->xwindow,
+                              parent_private->xwindow));
+      if (!SetParent (window_private->xwindow, parent_private->xwindow))
+       g_warning ("gdk_window_reparent: SetParent failed");
+
+      if (!MoveWindow (window_private->xwindow,
+                      x, y,
+                      window_private->width, window_private->height,
+                      TRUE))
+       g_warning ("gdk_window_reparent: MoveWindow failed");
+    }
+  
+  window_private->parent = new_parent;
+
+  if (old_parent_private)
+    old_parent_private->children = g_list_remove (old_parent_private->children, window);
+
+  if ((old_parent_private &&
+       (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) ||
+      (!old_parent_private && parent_private->guffaw_gravity))
+    gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity);
+  
+  parent_private->children = g_list_prepend (parent_private->children, window);
+}
+
+void
+gdk_window_clear (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+
+  if (!private->destroyed)
+    {
+      gdk_window_clear_area (window, 0, 0, private->width, private->height);
+    }
+}
+
+
+void
+gdk_window_clear_area (GdkWindow *window,
+                      gint       x,
+                      gint       y,
+                      gint       width,
+                      gint       height)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  
+  if (!private->destroyed)
+    {
+      HDC hdc;
+
+      if (width == -1)
+       width = G_MAXSHORT/2;           /* Yeah, right */
+      if (height == -1)
+       height = G_MAXSHORT/2;
+      GDK_NOTE (MISC, g_print ("gdk_window_clear_area: %#x %dx%d@+%d+%d\n",
+                              private->xwindow, width, height, x, y));
+      hdc = GetDC (private->xwindow);
+      IntersectClipRect (hdc, x, y, x + width, y + height);
+      SendMessage (private->xwindow, WM_ERASEBKGND, (WPARAM) hdc, 0);
+      ReleaseDC (private->xwindow, hdc);
+    }
+}
+
+void
+gdk_window_clear_area_e (GdkWindow *window,
+                        gint       x,
+                        gint       y,
+                        gint       width,
+                        gint       height)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  
+  if (!private->destroyed)
+    {
+      RECT rect;
+
+      GDK_NOTE (MISC, g_print ("gdk_window_clear_area_e: %#x %dx%d@+%d+%d\n",
+                              private->xwindow, width, height, x, y));
+
+      rect.left = x;
+      rect.right = x + width;
+      rect.top = y;
+      rect.bottom = y + height;
+      if (!InvalidateRect (private->xwindow, &rect, TRUE))
+       g_warning ("gdk_window_clear_area_e: InvalidateRect failed");
+      UpdateWindow (private->xwindow);
+    }
+}
+
+void
+gdk_window_copy_area (GdkWindow    *window,
+                     GdkGC        *gc,
+                     gint          x,
+                     gint          y,
+                     GdkWindow    *source_window,
+                     gint          source_x,
+                     gint          source_y,
+                     gint          width,
+                     gint          height)
+{
+  GdkWindowPrivate *src_private;
+  GdkWindowPrivate *dest_private;
+  GdkGCPrivate *gc_private;
+  
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (gc != NULL);
+  
+  if (source_window == NULL)
+    source_window = window;
+  
+  src_private = (GdkWindowPrivate*) source_window;
+  dest_private = (GdkWindowPrivate*) window;
+  gc_private = (GdkGCPrivate*) gc;
+  
+  if (!src_private->destroyed && !dest_private->destroyed)
+    {
+      HDC hdcDest, hdcSrc;
+
+      if ((hdcDest = GetDC (dest_private->xwindow)) == NULL)
+       g_warning ("gdk_window_copy_area: GetDC failed");
+
+      if ((hdcSrc = GetDC (src_private->xwindow)) == NULL)
+       g_warning ("gdk_window_copy_area: GetDC failed");
+
+      if (!BitBlt (hdcDest, x, y, width, height, hdcSrc, source_x, source_y, SRCCOPY))
+       g_warning ("gdk_window_copy_area: BitBlt failed");
+
+      ReleaseDC (dest_private->xwindow, hdcDest);
+      ReleaseDC (src_private->xwindow, hdcSrc);
+    }
+}
+
+void
+gdk_window_raise (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  
+  if (!private->destroyed)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_raise: %#x\n", private->xwindow));
+
+      if (!BringWindowToTop (private->xwindow))
+       g_warning ("gdk_window_raise: BringWindowToTop failed");
+    }
+}
+
+void
+gdk_window_lower (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  
+  if (!private->destroyed)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_lower: %#x\n", private->xwindow));
+
+      if (!SetWindowPos (private->xwindow, HWND_BOTTOM, 0, 0, 0, 0,
+                        SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE))
+       g_warning ("gdk_window_lower: SetWindowPos failed");
+    }
+}
+
+void
+gdk_window_set_user_data (GdkWindow *window,
+                         gpointer   user_data)
+{
+  g_return_if_fail (window != NULL);
+  
+  window->user_data = user_data;
+}
+
+void
+gdk_window_set_hints (GdkWindow *window,
+                     gint       x,
+                     gint       y,
+                     gint       min_width,
+                     gint       min_height,
+                     gint       max_width,
+                     gint       max_height,
+                     gint       flags)
+{
+  GdkWindowPrivate *private;
+  WINDOWPLACEMENT size_hints;
+  RECT rect;
+  DWORD dwStyle;
+  DWORD dwExStyle;
+  int diff;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return;
+  
+  GDK_NOTE (MISC, g_print ("gdk_window_set_hints: %#x %dx%d..%dx%d @+%d+%d\n",
+                          private->xwindow,
+                          min_width, min_height, max_width, max_height,
+                          x, y));
+
+  private->hint_flags = flags;
+  size_hints.length = sizeof (size_hints);
+
+  if (flags)
+    {
+      if (flags & GDK_HINT_POS)
+       if (!GetWindowPlacement (private->xwindow, &size_hints))
+         g_warning ("gdk_window_set_hints: GetWindowPlacement failed");
+       else
+         {
+           GDK_NOTE (MISC, g_print ("...rcNormalPosition:"
+                                    " (%d,%d)--(%d,%d)\n",
+                                    size_hints.rcNormalPosition.left,
+                                    size_hints.rcNormalPosition.top,
+                                    size_hints.rcNormalPosition.right,
+                                    size_hints.rcNormalPosition.bottom));
+           /* What are the corresponding window coordinates for client
+            * area coordinates x, y
+            */
+           rect.left = x;
+           rect.top = y;
+           rect.right = rect.left + 200;       /* dummy */
+           rect.bottom = rect.top + 200;
+           dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+           dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+           AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+           size_hints.flags = 0;
+           size_hints.showCmd = SW_SHOWNA;
+
+           /* Set the normal position hint to that location, with unchanged
+            * width and height.
+            */
+           diff = size_hints.rcNormalPosition.left - rect.left;
+           size_hints.rcNormalPosition.left = rect.left;
+           size_hints.rcNormalPosition.right -= diff;
+           diff = size_hints.rcNormalPosition.top - rect.top;
+           size_hints.rcNormalPosition.top = rect.top;
+           size_hints.rcNormalPosition.bottom -= diff;
+           GDK_NOTE (MISC, g_print ("...setting: (%d,%d)--(%d,%d)\n",
+                                    size_hints.rcNormalPosition.left,
+                                    size_hints.rcNormalPosition.top,
+                                    size_hints.rcNormalPosition.right,
+                                    size_hints.rcNormalPosition.bottom));
+           if (!SetWindowPlacement (private->xwindow, &size_hints))
+             g_warning ("gdk_window_set_hints: SetWindowPlacement failed");
+           private->hint_x = rect.left;
+           private->hint_y = rect.top;
+         }
+
+      if (flags & GDK_HINT_MIN_SIZE)
+       {
+         rect.left = 0;
+         rect.top = 0;
+         rect.right = min_width;
+         rect.bottom = min_height;
+         dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+         dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+         AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+         private->hint_min_width = rect.right - rect.left;
+         private->hint_min_height = rect.bottom - rect.top;
+
+         /* Also chek if he current size of the window is in bounds. */
+         GetClientRect (private->xwindow, &rect);
+         if (rect.right < min_width && rect.bottom < min_height)
+           gdk_window_resize (window, min_width, min_height);
+         else if (rect.right < min_width)
+           gdk_window_resize (window, min_width, rect.bottom);
+         else if (rect.bottom < min_height)
+           gdk_window_resize (window, rect.right, min_height);
+       }
+      if (flags & GDK_HINT_MAX_SIZE)
+       {
+         rect.left = 0;
+         rect.top = 0;
+         rect.right = max_width;
+         rect.bottom = max_height;
+         dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+         dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+         AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+         private->hint_max_width = rect.right - rect.left;
+         private->hint_max_height = rect.bottom - rect.top;
+         /* Again, check if the window is too large currently. */
+         GetClientRect (private->xwindow, &rect);
+         if (rect.right > max_width && rect.bottom > max_height)
+           gdk_window_resize (window, max_width, max_height);
+         else if (rect.right > max_width)
+           gdk_window_resize (window, max_width, rect.bottom);
+         else if (rect.bottom > max_height)
+           gdk_window_resize (window, rect.right, max_height);
+       }
+    }
+}
+
+void 
+gdk_window_set_geometry_hints (GdkWindow      *window,
+                              GdkGeometry    *geometry,
+                              GdkWindowHints  geom_mask)
+{
+  GdkWindowPrivate *private;
+  WINDOWPLACEMENT size_hints;
+  RECT rect;
+  DWORD dwStyle;
+  DWORD dwExStyle;
+  int diff;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return;
+  
+  size_hints.length = sizeof (size_hints);
+
+  private->hint_flags = geom_mask;
+
+  if (geom_mask & GDK_HINT_POS)
+    ; /* XXX */
+
+  if (geom_mask & GDK_HINT_MIN_SIZE)
+    {
+      rect.left = 0;
+      rect.top = 0;
+      rect.right = geometry->min_width;
+      rect.bottom = geometry->min_height;
+      dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+      dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+      AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+      private->hint_min_width = rect.right - rect.left;
+      private->hint_min_height = rect.bottom - rect.top;
+
+      /* Also check if he current size of the window is in bounds */
+      GetClientRect (private->xwindow, &rect);
+      if (rect.right < geometry->min_width
+         && rect.bottom < geometry->min_height)
+       gdk_window_resize (window, geometry->min_width, geometry->min_height);
+      else if (rect.right < geometry->min_width)
+       gdk_window_resize (window, geometry->min_width, rect.bottom);
+      else if (rect.bottom < geometry->min_height)
+       gdk_window_resize (window, rect.right, geometry->min_height);
+    }
+  
+  if (geom_mask & GDK_HINT_MAX_SIZE)
+    {
+      rect.left = 0;
+      rect.top = 0;
+      rect.right = geometry->max_width;
+      rect.bottom = geometry->max_height;
+      dwStyle = GetWindowLong (private->xwindow, GWL_STYLE);
+      dwExStyle = GetWindowLong (private->xwindow, GWL_EXSTYLE);
+      AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+      private->hint_max_width = rect.right - rect.left;
+      private->hint_max_height = rect.bottom - rect.top;
+
+      /* Again, check if the window is too large currently. */
+      GetClientRect (private->xwindow, &rect);
+      if (rect.right > geometry->max_width
+         && rect.bottom > geometry->max_height)
+       gdk_window_resize (window, geometry->max_width, geometry->max_height);
+      else if (rect.right > geometry->max_width)
+       gdk_window_resize (window, geometry->max_width, rect.bottom);
+      else if (rect.bottom > geometry->max_height)
+       gdk_window_resize (window, rect.right, geometry->max_height);
+    }
+  
+  /* I don't know what to do when called with zero base_width and height. */
+  if (geom_mask & GDK_HINT_BASE_SIZE
+      && geometry->base_width > 0
+      && geometry->base_height > 0)
+    if (!GetWindowPlacement (private->xwindow, &size_hints))
+      g_warning ("gdk_window_set_hints: GetWindowPlacement failed");
+    else
+      {
+       GDK_NOTE (MISC, g_print ("gdk_window_set_geometry_hints:"
+                                " rcNormalPosition: (%d,%d)--(%d,%d)\n",
+                                size_hints.rcNormalPosition.left,
+                                size_hints.rcNormalPosition.top,
+                                size_hints.rcNormalPosition.right,
+                                size_hints.rcNormalPosition.bottom));
+       size_hints.rcNormalPosition.right =
+         size_hints.rcNormalPosition.left + geometry->base_width;
+       size_hints.rcNormalPosition.bottom =
+         size_hints.rcNormalPosition.top + geometry->base_height;
+       GDK_NOTE (MISC, g_print ("...setting: rcNormal: (%d,%d)--(%d,%d)\n",
+                                size_hints.rcNormalPosition.left,
+                                size_hints.rcNormalPosition.top,
+                                size_hints.rcNormalPosition.right,
+                                size_hints.rcNormalPosition.bottom));
+       if (!SetWindowPlacement (private->xwindow, &size_hints))
+         g_warning ("gdk_window_set_hints: SetWindowPlacement failed");
+      }
+  
+  if (geom_mask & GDK_HINT_RESIZE_INC)
+    {
+      /* XXX */
+    }
+  
+  if (geom_mask & GDK_HINT_ASPECT)
+    {
+      /* XXX */
+    }
+}
+
+void
+gdk_window_set_title (GdkWindow   *window,
+                     const gchar *title)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      if (!SetWindowText (private->xwindow, title))
+       g_warning ("gdk_window_set_title: SetWindowText failed");
+    }
+}
+
+void          
+gdk_window_set_role (GdkWindow   *window,
+                    const gchar *role)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+
+  GDK_NOTE (MISC, g_print ("gdk_window_set_role: %#x %s\n",
+                          private->xwindow, (role ? role : "NULL")));
+  /* XXX */
+}
+
+void          
+gdk_window_set_transient_for (GdkWindow *window, 
+                             GdkWindow *parent)
+{
+  GdkWindowPrivate *private;
+  GdkWindowPrivate *parent_private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  parent_private = (GdkWindowPrivate*) parent;
+
+  GDK_NOTE (MISC, g_print ("gdk_window_set_transient_for: %#x %#x\n",
+                          private->xwindow, parent_private->xwindow));
+  /* XXX */
+}
+
+void
+gdk_window_set_background (GdkWindow *window,
+                          GdkColor  *color)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  if (!private->destroyed)
+    {
+      GdkColormapPrivate *colormap_private =
+       (GdkColormapPrivate *) private->colormap;
+
+      GDK_NOTE (MISC, g_print ("gdk_window_set_background: %#x %s\n",
+                              private->xwindow, 
+                              gdk_color_to_string (color)));
+
+      if (private->bg_type == GDK_WIN32_BG_PIXMAP)
+       {
+         if (private->bg_pixmap != NULL)
+           {
+             gdk_pixmap_unref (private->bg_pixmap);
+             private->bg_pixmap = NULL;
+           }
+         private->bg_type = GDK_WIN32_BG_NORMAL;
+       }
+#ifdef MULTIPLE_WINDOW_CLASSES
+      if (colormap_private != NULL
+             && colormap_private->xcolormap->rc_palette)
+       {
+         /* If we are on a palettized display we can't use the window
+          * class background brush, but must handle WM_ERASEBKGND.
+          * At least, I think so.
+          */
+#endif
+         private->bg_type = GDK_WIN32_BG_PIXEL;
+         private->bg_pixel = *color;
+#ifdef MULTIPLE_WINDOW_CLASSES
+       }
+      else
+       {
+         /* Non-palettized display; just set the window class background
+            brush. */
+         HBRUSH hbr;
+         HGDIOBJ oldbrush;
+         COLORREF background;
+
+         background = RGB (color->red >> 8,
+                           color->green >> 8,
+                           color->blue >> 8);
+
+         if ((hbr = CreateSolidBrush (GetNearestColor (gdk_DC,
+                                                       background))) == NULL)
+           {
+             g_warning ("gdk_window_set_background: CreateSolidBrush failed");
+             return;
+           }
+
+         oldbrush = (HGDIOBJ) GetClassLong (private->xwindow,
+                                            GCL_HBRBACKGROUND);
+
+         if (SetClassLong (private->xwindow, GCL_HBRBACKGROUND,
+                           (LONG) hbr) == 0)
+           g_warning ("gdk_window_set_background: SetClassLong failed");
+
+         if (!DeleteObject (oldbrush))
+           g_warning ("gdk_window_set_background: DeleteObject failed");
+       }
+#endif
+    }
+}
+
+void
+gdk_window_set_back_pixmap (GdkWindow *window,
+                           GdkPixmap *pixmap,
+                           gint       parent_relative)
+{
+  GdkWindowPrivate *window_private;
+#ifdef MULTIPLE_WINDOW_CLASSES
+  GdkPixmapPrivate *pixmap_private;
+#endif
+
+  g_return_if_fail (window != NULL);
+  
+  window_private = (GdkWindowPrivate*) window;
+#ifdef MULTIPLE_WINDOW_CLASSES
+  pixmap_private = (GdkPixmapPrivate*) pixmap;
+#endif
+
+  if (!window_private->destroyed)
+    {
+      GdkColormapPrivate *colormap_private =
+       (GdkColormapPrivate *) window_private->colormap;
+      if (window_private->bg_type == GDK_WIN32_BG_PIXMAP)
+       {
+         if (window_private->bg_pixmap != NULL)
+           {
+             gdk_pixmap_unref (window_private->bg_pixmap);
+             window_private->bg_pixmap = NULL;
+           }
+         window_private->bg_type = GDK_WIN32_BG_NORMAL;
+       }
+      if (parent_relative)
+       {
+         window_private->bg_type = GDK_WIN32_BG_PARENT_RELATIVE;
+       }
+      else if (!pixmap)
+       {
+#ifdef MULTIPLE_WINDOW_CLASSES
+         SetClassLong (window_private->xwindow, GCL_HBRBACKGROUND,
+                       (LONG) GetStockObject (BLACK_BRUSH));
+#endif
+       }
+#ifdef MULTIPLE_WINDOW_CLASSES
+      else if (colormap_private->xcolormap->rc_palette)
+       {
+         /* Must do the background painting in the
+          * WM_ERASEBKGND handler.
+          */
+         window_private->bg_type = GDK_WIN32_BG_PIXMAP;
+         window_private->bg_pixmap = pixmap;
+         gdk_pixmap_ref (pixmap);
+       }
+      else if (pixmap_private->width <= 8
+              && pixmap_private->height <= 8)
+       {
+         /* We can use small pixmaps directly as background brush */
+         SetClassLong (window_private->xwindow, GCL_HBRBACKGROUND,
+                       (LONG) CreatePatternBrush (pixmap_private->xwindow));
+       }
+#endif
+      else
+       {
+         /* We must cache the pixmap in the WindowPrivate and
+          * paint it each time we get WM_ERASEBKGND
+          */
+         window_private->bg_type = GDK_WIN32_BG_PIXMAP;
+         window_private->bg_pixmap = pixmap;
+         gdk_pixmap_ref (pixmap);
+       }
+    }
+}
+
+void
+gdk_window_set_cursor (GdkWindow *window,
+                      GdkCursor *cursor)
+{
+  GdkWindowPrivate *window_private;
+  GdkCursorPrivate *cursor_private;
+  HCURSOR xcursor;
+  
+  g_return_if_fail (window != NULL);
+  
+  window_private = (GdkWindowPrivate*) window;
+  cursor_private = (GdkCursorPrivate*) cursor;
+  
+  if (!window_private->destroyed)
+    {
+      if (!cursor)
+       xcursor = LoadCursor (NULL, IDC_ARROW);
+      else
+       xcursor = cursor_private->xcursor;
+
+      GDK_NOTE (MISC, g_print ("gdk_window_set_cursor: %#x %#x\n",
+                              window_private->xwindow, xcursor));
+#ifdef MULTIPLE_WINDOW_CLASSES
+      if (!SetClassLong (window_private->xwindow, GCL_HCURSOR, (LONG) xcursor))
+       g_warning ("gdk_window_set_cursor: SetClassLong failed");
+#else
+      window_private->xcursor = xcursor;
+#endif
+      SetCursor (xcursor);
+    }
+}
+
+void
+gdk_window_set_colormap (GdkWindow   *window,
+                        GdkColormap *colormap)
+{
+  GdkWindowPrivate *window_private;
+  GdkColormapPrivate *colormap_private;
+  
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (colormap != NULL);
+  
+  window_private = (GdkWindowPrivate*) window;
+  colormap_private = (GdkColormapPrivate*) colormap;
+  
+  if (!window_private->destroyed)
+    {
+      /* XXX ??? */
+      GDK_NOTE (MISC, g_print ("gdk_window_set_colormap: %#x %#x\n",
+                              window_private->xwindow,
+                              colormap_private->xcolormap));
+      if (window_private->colormap)
+       gdk_colormap_unref (window_private->colormap);
+      window_private->colormap = colormap;
+      gdk_colormap_ref (window_private->colormap);
+      
+      if (window_private->window_type != GDK_WINDOW_TOPLEVEL)
+       gdk_window_add_colormap_windows (window);
+    }
+}
+
+void
+gdk_window_get_user_data (GdkWindow *window,
+                         gpointer  *data)
+{
+  g_return_if_fail (window != NULL);
+  
+  *data = window->user_data;
+}
+
+void
+gdk_window_get_geometry (GdkWindow *window,
+                        gint      *x,
+                        gint      *y,
+                        gint      *width,
+                        gint      *height,
+                        gint      *depth)
+{
+  GdkWindowPrivate *window_private;
+  
+  if (!window)
+    window = (GdkWindow*) &gdk_root_parent;
+  
+  window_private = (GdkWindowPrivate*) window;
+  
+  if (!window_private->destroyed)
+    {
+      RECT rect;
+
+      if (!GetClientRect (window_private->xwindow, &rect))
+       g_warning ("gdk_window_get_geometry: GetClientRect failed");
+
+      if (x)
+       *x = rect.left;
+      if (y)
+       *y = rect.top;
+      if (width)
+       *width = rect.right - rect.left;
+      if (height)
+       *height = rect.bottom - rect.top;
+      if (depth)
+       *depth = gdk_window_get_visual (window)->depth;
+    }
+}
+
+void
+gdk_window_get_position (GdkWindow *window,
+                        gint      *x,
+                        gint      *y)
+{
+  GdkWindowPrivate *window_private;
+  
+  g_return_if_fail (window != NULL);
+  
+  window_private = (GdkWindowPrivate*) window;
+  
+  if (x)
+    *x = window_private->x;
+  if (y)
+    *y = window_private->y;
+}
+
+void
+gdk_window_get_size (GdkWindow *window,
+                    gint       *width,
+                    gint       *height)
+{
+  GdkWindowPrivate *window_private;
+  
+  g_return_if_fail (window != NULL);
+  
+  window_private = (GdkWindowPrivate*) window;
+  
+  if (width)
+    *width = window_private->width;
+  if (height)
+    *height = window_private->height;
+}
+
+GdkVisual*
+gdk_window_get_visual (GdkWindow *window)
+{
+  GdkWindowPrivate *window_private;
+   
+  g_return_val_if_fail (window != NULL, NULL);
+
+  window_private = (GdkWindowPrivate*) window;
+  /* Huh? ->parent is never set for a pixmap. We should just return
+   * null immeditately
+   */
+  while (window_private && (window_private->window_type == GDK_WINDOW_PIXMAP))
+    window_private = (GdkWindowPrivate*) window_private->parent;
+  
+  if (window_private && !window_private->destroyed)
+    {
+       if (window_private->colormap == NULL)
+        {
+           return gdk_visual_get_system (); /* XXX ??? */
+        }
+       else
+        return ((GdkColormapPrivate *)window_private->colormap)->visual;
+    }
+  
+  return NULL;
+}
+
+GdkColormap*
+gdk_window_get_colormap (GdkWindow *window)
+{
+  GdkWindowPrivate *window_private;
+  
+  g_return_val_if_fail (window != NULL, NULL);
+  window_private = (GdkWindowPrivate*) window;
+
+  g_return_val_if_fail (window_private->window_type != GDK_WINDOW_PIXMAP, NULL);
+  if (!window_private->destroyed)
+    {
+      if (window_private->colormap == NULL)
+       {
+         return gdk_colormap_get_system (); /* XXX ??? */
+        }
+       else
+        return window_private->colormap;
+    }
+  
+  return NULL;
+}
+
+GdkWindowType
+gdk_window_get_type (GdkWindow *window)
+{
+  GdkWindowPrivate *window_private;
+
+  g_return_val_if_fail (window != NULL, (GdkWindowType) -1);
+
+  window_private = (GdkWindowPrivate*) window;
+  return window_private->window_type;
+}
+
+gint
+gdk_window_get_origin (GdkWindow *window,
+                      gint      *x,
+                      gint      *y)
+{
+  GdkWindowPrivate *private;
+  gint return_val;
+  gint tx = 0;
+  gint ty = 0;
+
+  g_return_val_if_fail (window != NULL, 0);
+
+  private = (GdkWindowPrivate*) window;
+
+  if (!private->destroyed)
+    {
+      POINT pt;
+
+      pt.x = 0;
+      pt.y = 0;
+      ClientToScreen (private->xwindow, &pt);
+      tx = pt.x;
+      ty = pt.y;
+      return_val = 1;
+    }
+  else
+    return_val = 0;
+  
+  if (x)
+    *x = tx;
+  if (y)
+    *y = ty;
+  
+  return return_val;
+}
+
+gboolean
+gdk_window_get_deskrelative_origin (GdkWindow *window,
+                                   gint      *x,
+                                   gint      *y)
+{
+  return gdk_window_get_origin (window, x, y);
+}
+
+void
+gdk_window_get_root_origin (GdkWindow *window,
+                           gint      *x,
+                           gint      *y)
+{
+  GdkWindowPrivate *private;
+  POINT pt;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (x)
+    *x = 0;
+  if (y)
+    *y = 0;
+  if (private->destroyed)
+    return;
+      
+  while (private->parent && ((GdkWindowPrivate*) private->parent)->parent)
+    private = (GdkWindowPrivate*) private->parent;
+  if (private->destroyed)
+    return;
+
+  pt.x = 0;
+  pt.y = 0;
+  ClientToScreen (private->xwindow, &pt);
+  if (x)
+    *x = pt.x;
+  if (y)
+    *y = pt.y;
+}
+
+GdkWindow*
+gdk_window_get_pointer (GdkWindow       *window,
+                       gint            *x,
+                       gint            *y,
+                       GdkModifierType *mask)
+{
+  GdkWindowPrivate *private;
+  GdkWindow *return_val;
+  POINT pointc, point;
+  HWND hwnd, hwndc;
+
+  if (!window)
+    window = (GdkWindow*) &gdk_root_parent;
+
+  private = (GdkWindowPrivate*) window;
+
+  return_val = NULL;
+  GetCursorPos (&pointc);
+  point = pointc;
+  ScreenToClient (private->xwindow, &point);
+
+  if (x)
+    *x = point.x;
+  if (y)
+    *y = point.y;
+
+  hwnd = WindowFromPoint (point);
+  point = pointc;
+  ScreenToClient (hwnd, &point);
+  
+  do {
+    hwndc = ChildWindowFromPoint (hwnd, point);
+    ClientToScreen (hwnd, &point);
+    ScreenToClient (hwndc, &point);
+  } while (hwndc != hwnd && (hwnd = hwndc, 1));        /* Ouch! */
+
+  return_val = gdk_window_lookup (hwnd);
+
+  if (mask)
+    {
+      BYTE kbd[256];
+
+      GetKeyboardState (kbd);
+      *mask = 0;
+      if (kbd[VK_SHIFT] & 0x80)
+       *mask |= GDK_SHIFT_MASK;
+      if (kbd[VK_CAPITAL] & 0x80)
+       *mask |= GDK_LOCK_MASK;
+      if (kbd[VK_CONTROL] & 0x80)
+       *mask |= GDK_CONTROL_MASK;
+      if (kbd[VK_MENU] & 0x80)
+       *mask |= GDK_MOD1_MASK;
+      if (kbd[VK_LBUTTON] & 0x80)
+       *mask |= GDK_BUTTON1_MASK;
+      if (kbd[VK_MBUTTON] & 0x80)
+       *mask |= GDK_BUTTON2_MASK;
+      if (kbd[VK_RBUTTON] & 0x80)
+       *mask |= GDK_BUTTON3_MASK;
+    }
+  
+  return return_val;
+}
+
+GdkWindow*
+gdk_window_at_pointer (gint *win_x,
+                      gint *win_y)
+{
+  GdkWindowPrivate *private;
+  GdkWindow *window;
+  POINT point, pointc;
+  HWND hwnd, hwndc;
+  RECT rect;
+
+  private = &gdk_root_parent;
+
+  GetCursorPos (&pointc);
+  point = pointc;
+  hwnd = WindowFromPoint (point);
+
+  if (hwnd == NULL)
+    {
+      window = (GdkWindow *) &gdk_root_parent;
+      if (win_x)
+       *win_x = pointc.x;
+      if (win_y)
+       *win_y = pointc.y;
+      return window;
+    }
+      
+  ScreenToClient (hwnd, &point);
+
+  do {
+    hwndc = ChildWindowFromPoint (hwnd, point);
+    ClientToScreen (hwnd, &point);
+    ScreenToClient (hwndc, &point);
+  } while (hwndc != hwnd && (hwnd = hwndc, 1));
+
+  window = gdk_window_lookup (hwnd);
+
+  if (window && (win_x || win_y))
+    {
+      GetClientRect (hwnd, &rect);
+      if (win_x)
+       *win_x = point.x - rect.left;
+      if (win_y)
+       *win_y = point.y - rect.top;
+    }
+
+  GDK_NOTE (MISC, g_print ("gdk_window_at_pointer: +%d+%d %#x%s\n",
+                          point.x, point.y, hwnd,
+                          (window == NULL ? " NULL" : "")));
+
+  return window;
+}
+
+GdkWindow*
+gdk_window_get_parent (GdkWindow *window)
+{
+  g_return_val_if_fail (window != NULL, NULL);
+
+  return ((GdkWindowPrivate*) window)->parent;
+}
+
+GdkWindow*
+gdk_window_get_toplevel (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  private = (GdkWindowPrivate*) window;
+
+  while (private->window_type == GDK_WINDOW_CHILD)
+    {
+      window = ((GdkWindowPrivate*) window)->parent;
+      private = (GdkWindowPrivate*) window;
+    }
+
+  return window;
+}
+
+GList*
+gdk_window_get_children (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+  GList *children;
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return NULL;
+
+  /* XXX ??? */
+  g_warning ("gdk_window_get_children ???");
+  children = NULL;
+
+  return children;
+}
+
+GdkEventMask  
+gdk_window_get_events (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+  GdkEventMask event_mask;
+
+  g_return_val_if_fail (window != NULL, 0);
+
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return 0;
+
+  event_mask = 0;
+
+  event_mask = private->event_mask;
+
+  return event_mask;
+}
+
+void          
+gdk_window_set_events (GdkWindow   *window,
+                      GdkEventMask event_mask)
+{
+  GdkWindowPrivate *private;
+
+  g_return_if_fail (window != NULL);
+
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return;
+
+  private->event_mask = event_mask;
+}
+
+void
+gdk_window_add_colormap_windows (GdkWindow *window)
+{
+  g_warning ("gdk_window_add_colormap_windows not implemented"); /* XXX */
+}
+
+/*
+ * This needs the X11 shape extension.
+ * If not available, shaped windows will look
+ * ugly, but programs still work.    Stefan Wille
+ */
+void
+gdk_window_shape_combine_mask (GdkWindow *window,
+                              GdkBitmap *mask,
+                              gint x, gint y)
+{
+  GdkWindowPrivate *window_private;
+
+  g_return_if_fail (window != NULL);
+
+  window_private = (GdkWindowPrivate*) window;
+  
+  if (!mask)
+    {
+      GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %#x none\n",
+                              window_private->xwindow));
+      SetWindowRgn (window_private->xwindow, NULL, TRUE);
+    }
+  else
+    {
+      GdkPixmapPrivate *pixmap_private;
+      HRGN hrgn;
+      DWORD dwStyle;
+      DWORD dwExStyle;
+      RECT rect;
+
+      /* Convert mask bitmap to region */
+      pixmap_private = (GdkPixmapPrivate*) mask;
+      hrgn = BitmapToRegion (pixmap_private->xwindow);
+
+      GDK_NOTE (MISC, g_print ("gdk_window_shape_combine_mask: %#x %#x\n",
+                              window_private->xwindow,
+                              pixmap_private->xwindow));
+
+      /* SetWindowRgn wants window (not client) coordinates */ 
+      dwStyle = GetWindowLong (window_private->xwindow, GWL_STYLE);
+      dwExStyle = GetWindowLong (window_private->xwindow, GWL_EXSTYLE);
+      GetClientRect (window_private->xwindow, &rect);
+      AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+      OffsetRgn (hrgn, -rect.left, -rect.top);
+
+      OffsetRgn (hrgn, x, y);
+
+      /* If this is a top-level window, add the title bar to the region */
+      if (window_private->window_type == GDK_WINDOW_TOPLEVEL)
+       {
+         CombineRgn (hrgn, hrgn,
+                     CreateRectRgn (0, 0, rect.right - rect.left, -rect.top),
+                     RGN_OR);
+       }
+      
+      SetWindowRgn (window_private->xwindow, hrgn, TRUE);
+    }
+}
+
+void          
+gdk_window_add_filter (GdkWindow     *window,
+                      GdkFilterFunc  function,
+                      gpointer       data)
+{
+  GdkWindowPrivate *private;
+  GList *tmp_list;
+  GdkEventFilter *filter;
+
+  private = (GdkWindowPrivate*) window;
+  if (private && private->destroyed)
+    return;
+
+  if (private)
+    tmp_list = private->filters;
+  else
+    tmp_list = gdk_default_filters;
+
+  while (tmp_list)
+    {
+      filter = (GdkEventFilter *)tmp_list->data;
+      if ((filter->function == function) && (filter->data == data))
+       return;
+      tmp_list = tmp_list->next;
+    }
+
+  filter = g_new (GdkEventFilter, 1);
+  filter->function = function;
+  filter->data = data;
+
+  if (private)
+    private->filters = g_list_append (private->filters, filter);
+  else
+    gdk_default_filters = g_list_append (gdk_default_filters, filter);
+}
+
+void
+gdk_window_remove_filter (GdkWindow     *window,
+                         GdkFilterFunc  function,
+                         gpointer       data)
+{
+  GdkWindowPrivate *private;
+  GList *tmp_list, *node;
+  GdkEventFilter *filter;
+
+  private = (GdkWindowPrivate*) window;
+
+  if(private)
+    tmp_list = private->filters;
+  else
+    tmp_list = gdk_default_filters;
+
+  while (tmp_list)
+    {
+      filter = (GdkEventFilter *)tmp_list->data;
+      node = tmp_list;
+      tmp_list = tmp_list->next;
+
+      if ((filter->function == function) && (filter->data == data))
+       {
+         if(private)
+           private->filters = g_list_remove_link (private->filters, node);
+         else
+           gdk_default_filters = g_list_remove_link (gdk_default_filters, tmp_list);
+         g_list_free_1 (node);
+         g_free (filter);
+         
+         return;
+       }
+    }
+}
+
+void
+gdk_window_set_override_redirect (GdkWindow *window,
+                                 gboolean   override_redirect)
+{
+  g_warning ("gdk_window_set_override_redirect not implemented"); /* XXX */
+}
+
+void          
+gdk_window_set_icon (GdkWindow *window, 
+                    GdkWindow *icon_window,
+                    GdkPixmap *pixmap,
+                    GdkBitmap *mask)
+{
+  g_warning ("gdk_window_set_icon not implemented"); /* XXX */
+}
+
+void          
+gdk_window_set_icon_name (GdkWindow *window, 
+                         gchar     *name)
+{
+  GdkWindowPrivate *window_private;
+
+  g_return_if_fail (window != NULL);
+  window_private = (GdkWindowPrivate*) window;
+  if (window_private->destroyed)
+    return;
+
+  if (!SetWindowText (window_private->xwindow, name))
+    g_warning ("gdk_window_set_icon_name: SetWindowText failed");
+}
+
+void          
+gdk_window_set_group (GdkWindow *window, 
+                     GdkWindow *leader)
+{
+  g_warning ("gdk_window_set_group not implemented"); /* XXX */
+}
+
+void
+gdk_window_set_decorations (GdkWindow      *window,
+                           GdkWMDecoration decorations)
+{
+  GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
+  LONG style, exstyle;
+
+  style = GetWindowLong (window_private->xwindow, GWL_STYLE);
+  exstyle = GetWindowLong (window_private->xwindow, GWL_EXSTYLE);
+
+  style &= (WS_OVERLAPPED|WS_POPUP|WS_CHILD|WS_MINIMIZE|WS_VISIBLE|WS_DISABLED
+           |WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZE);
+
+  exstyle &= (WS_EX_TOPMOST|WS_EX_TRANSPARENT);
+
+  if (decorations & GDK_DECOR_ALL)
+    style |= (WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX);
+  if (decorations & GDK_DECOR_BORDER)
+    style |= (WS_BORDER);
+  if (decorations & GDK_DECOR_RESIZEH)
+    style |= (WS_THICKFRAME);
+  if (decorations & GDK_DECOR_TITLE)
+    style |= (WS_CAPTION);
+  if (decorations & GDK_DECOR_MENU)
+    style |= (WS_SYSMENU);
+  if (decorations & GDK_DECOR_MINIMIZE)
+    style |= (WS_MINIMIZEBOX);
+  if (decorations & GDK_DECOR_MAXIMIZE)
+    style |= (WS_MAXIMIZEBOX);
+  
+  SetWindowLong (window_private->xwindow, GWL_STYLE, style);
+}
+
+void
+gdk_window_set_functions (GdkWindow    *window,
+                         GdkWMFunction functions)
+{
+  GdkWindowPrivate *window_private = (GdkWindowPrivate *) window;
+  LONG style, exstyle;
+
+  style = GetWindowLong (window_private->xwindow, GWL_STYLE);
+  exstyle = GetWindowLong (window_private->xwindow, GWL_EXSTYLE);
+
+  style &= (WS_OVERLAPPED|WS_POPUP|WS_CHILD|WS_MINIMIZE|WS_VISIBLE|WS_DISABLED
+           |WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_MAXIMIZE|WS_CAPTION|WS_BORDER
+           |WS_SYSMENU);
+
+  exstyle &= (WS_EX_TOPMOST|WS_EX_TRANSPARENT);
+
+  if (functions & GDK_FUNC_ALL)
+    style |= (WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX);
+  if (functions & GDK_FUNC_RESIZE)
+    style |= (WS_THICKFRAME);
+  if (functions & GDK_FUNC_MOVE)
+    style |= (WS_THICKFRAME);
+  if (functions & GDK_FUNC_MINIMIZE)
+    style |= (WS_MINIMIZEBOX);
+  if (functions & GDK_FUNC_MAXIMIZE)
+    style |= (WS_MAXIMIZEBOX);
+  
+  SetWindowLong (window_private->xwindow, GWL_STYLE, style);
+}
+
+GList *
+gdk_window_get_toplevels (void)
+{
+  GList *new_list = NULL;
+  GList *tmp_list;
+
+  tmp_list = gdk_root_parent.children;
+  while (tmp_list)
+    {
+      new_list = g_list_prepend (new_list, tmp_list->data);
+      tmp_list = tmp_list->next;
+    }
+
+  return new_list;
+}
+
+/* 
+ * propagate the shapes from all child windows of a GDK window to the parent 
+ * window. Shamelessly ripped from Enlightenment's code
+ * 
+ * - Raster
+ */
+
+static void
+QueryTree (HWND hwnd,
+          HWND **children,
+          gint *nchildren)
+{
+  guint i, n;
+  HWND child;
+
+  n = 0;
+  do {
+    if (n == 0)
+      child = GetWindow (hwnd, GW_CHILD);
+    else
+      child = GetWindow (child, GW_HWNDNEXT);
+    if (child != NULL)
+      n++;
+  } while (child != NULL);
+
+  if (n > 0)
+    {
+      *children = g_new (HWND, n);
+      for (i = 0; i < n; i++)
+       {
+         if (i == 0)
+           child = GetWindow (hwnd, GW_CHILD);
+         else
+           child = GetWindow (child, GW_HWNDNEXT);
+         *children[i] = child;
+       }
+    }
+}
+
+static void
+gdk_propagate_shapes (HANDLE   win,
+                     gboolean merge)
+{
+   RECT emptyRect;
+   HRGN region, childRegion;
+   RECT rect;
+   HWND *list = NULL;
+   gint i, num;
+
+   SetRectEmpty (&emptyRect);
+   region = CreateRectRgnIndirect (&emptyRect);
+   if (merge)
+     GetWindowRgn (win, region);
+   
+   QueryTree (win, &list, &num);
+   if (list != NULL)
+     {
+       WINDOWPLACEMENT placement;
+
+       placement.length = sizeof (WINDOWPLACEMENT);
+       /* go through all child windows and create/insert spans */
+       for (i = 0; i < num; i++)
+        {
+          GetWindowPlacement (list[i], &placement);
+          if (placement.showCmd = SW_SHOWNORMAL)
+            {
+              childRegion = CreateRectRgnIndirect (&emptyRect);
+              GetWindowRgn (list[i], childRegion);
+              CombineRgn (region, region, childRegion, RGN_OR);
+            }
+         }
+       SetWindowRgn (win, region, TRUE);
+     }
+}
+
+void
+gdk_window_set_child_shapes (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+   
+  g_return_if_fail (window != NULL);
+   
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return;
+
+  gdk_propagate_shapes ( private->xwindow, FALSE);
+}
+
+void
+gdk_window_merge_child_shapes (GdkWindow *window)
+{
+  GdkWindowPrivate *private;
+  
+  g_return_if_fail (window != NULL);
+  
+  private = (GdkWindowPrivate*) window;
+  if (private->destroyed)
+    return;
+
+  gdk_propagate_shapes (private->xwindow, TRUE);
+}
+
+/*************************************************************
+ * gdk_window_is_visible:
+ *     Check if the given window is mapped.
+ *   arguments:
+ *     window: 
+ *   results:
+ *     is the window mapped
+ *************************************************************/
+
+gboolean 
+gdk_window_is_visible (GdkWindow *window)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+
+  g_return_val_if_fail (window != NULL, FALSE);
+
+  return private->mapped;
+}
+
+/*************************************************************
+ * gdk_window_is_viewable:
+ *     Check if the window and all ancestors of the window
+ *     are mapped. (This is not necessarily "viewable" in
+ *     the X sense, since we only check as far as we have
+ *     GDK window parents, not to the root window)
+ *   arguments:
+ *     window:
+ *   results:
+ *     is the window viewable
+ *************************************************************/
+
+gboolean 
+gdk_window_is_viewable (GdkWindow *window)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+
+  g_return_val_if_fail (window != NULL, FALSE);
+
+  while (private && 
+        (private != &gdk_root_parent) &&
+        (private->window_type != GDK_WINDOW_FOREIGN))
+    {
+      if (!private->mapped)
+       return FALSE;
+
+      private = (GdkWindowPrivate *)private->parent;
+    }
+
+  return TRUE;
+}
+
+void          
+gdk_drawable_set_data (GdkDrawable   *drawable,
+                      const gchar   *key,
+                      gpointer       data,
+                      GDestroyNotify destroy_func)
+{
+  g_dataset_set_data_full (drawable, key, data, destroy_func);
+}
+
+
+/* Support for windows that can be guffaw-scrolled
+ * (See http://www.gtk.org/~otaylor/whitepapers/guffaw-scrolling.txt)
+ */
+
+static gboolean
+gdk_window_gravity_works (void)
+{
+  enum { UNKNOWN, NO, YES };
+  static gint gravity_works = UNKNOWN;
+
+  if (gravity_works == UNKNOWN)
+    {
+      GdkWindowAttr attr;
+      GdkWindow *parent;
+      GdkWindow *child;
+      gint y;
+      
+      attr.window_type = GDK_WINDOW_TEMP;
+      attr.wclass = GDK_INPUT_OUTPUT;
+      attr.x = 0;
+      attr.y = 0;
+      attr.width = 100;
+      attr.height = 100;
+      attr.event_mask = 0;
+      
+      parent = gdk_window_new (NULL, &attr, GDK_WA_X | GDK_WA_Y);
+      
+      attr.window_type = GDK_WINDOW_CHILD;
+      child = gdk_window_new (parent, &attr, GDK_WA_X | GDK_WA_Y);
+
+      gdk_window_set_static_win_gravity (child, TRUE);
+      
+      gdk_window_resize (parent, 100, 110);
+      gdk_window_move (parent, 0, -10);
+      gdk_window_move_resize (parent, 0, 0, 100, 100);
+      
+      gdk_window_resize (parent, 100, 110);
+      gdk_window_move (parent, 0, -10);
+      gdk_window_move_resize (parent, 0, 0, 100, 100);
+      
+      gdk_window_get_geometry (child, NULL, &y, NULL, NULL, NULL);
+      
+      gdk_window_destroy (parent);
+      gdk_window_destroy (child);
+  
+      gravity_works = ((y == -20) ? YES : NO);
+    }
+
+  return (gravity_works == YES);
+}
+
+static void
+gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+
+  g_return_if_fail (window != NULL);
+
+  GDK_NOTE (MISC,
+           g_print ("gdk_window_set_static_bit_gravity: Not implemented\n"));
+}
+
+static void
+gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+
+  g_return_if_fail (window != NULL);
+
+  GDK_NOTE (MISC,
+           g_print ("gdk_window_set_static_win_gravity: Not implemented\n"));
+}
+
+/*************************************************************
+ * gdk_window_set_static_gravities:
+ *     Set the bit gravity of the given window to static,
+ *     and flag it so all children get static subwindow
+ *     gravity.
+ *   arguments:
+ *     window: window for which to set static gravity
+ *     use_static: Whether to turn static gravity on or off.
+ *   results:
+ *     Does the XServer support static gravity?
+ *************************************************************/
+
+gboolean 
+gdk_window_set_static_gravities (GdkWindow *window,
+                                gboolean   use_static)
+{
+  GdkWindowPrivate *private = (GdkWindowPrivate *)window;
+  GList *tmp_list;
+
+  g_return_val_if_fail (window != NULL, FALSE);
+  
+  if (!use_static == !private->guffaw_gravity)
+    return TRUE;
+  
+  if (use_static && !gdk_window_gravity_works ())
+    return FALSE;
+
+  private->guffaw_gravity = use_static;
+
+  gdk_window_set_static_bit_gravity (window, use_static);
+
+  tmp_list = private->children;
+  while (tmp_list)
+    {
+      gdk_window_set_static_win_gravity (window, use_static);
+      
+      tmp_list = tmp_list->next;
+    }
+
+  return TRUE;
+}
diff --git a/gdk/win32/gdkx.h b/gdk/win32/gdkx.h
new file mode 100644 (file)
index 0000000..5086191
--- /dev/null
@@ -0,0 +1,59 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef __GDK_X_H__
+#define __GDK_X_H__
+
+#include <gdk/gdk.h>
+#include <gdk/gdkprivate.h>
+
+#include <time.h>
+#include <locale.h>
+
+#define GDK_ROOT_WINDOW()             ((guint32) HWND_DESKTOP)
+#define GDK_ROOT_PARENT()             ((GdkWindow *)&gdk_root_parent)
+#define GDK_DISPLAY()                 NULL
+#define GDK_WINDOW_XDISPLAY(win)      NULL
+#define GDK_WINDOW_XWINDOW(win)       (((GdkWindowPrivate*) win)->xwindow)
+#define GDK_IMAGE_XDISPLAY(image)     NULL
+#define GDK_IMAGE_XIMAGE(image)       (((GdkImagePrivate*) image)->ximage)
+#define GDK_GC_XDISPLAY(gc)           NULL
+#define GDK_GC_XGC(gc)                (((GdkGCPrivate*) gc)->xgc)
+#define GDK_COLORMAP_XDISPLAY(cmap)   NULL
+#define GDK_COLORMAP_XCOLORMAP(cmap)  (((GdkColormapPrivate*) cmap)->xcolormap)
+#define GDK_VISUAL_XVISUAL(vis)       (((GdkVisualPrivate*) vis)->xvisual)
+#define GDK_FONT_XDISPLAY(font)       NULL
+#define GDK_FONT_XFONT(font)          (((GdkFontPrivate*) font)->xfont)
+
+GdkVisual*   gdkx_visual_get   (VisualID xvisualid);
+/* XXX: Do not use this function until it is fixed. An X Colormap
+ *      is useless unless we also have the visual. */
+GdkColormap* gdkx_colormap_get (Colormap xcolormap);
+/* Functions to create GDK pixmaps and windows from their native equivalents */
+GdkPixmap    *gdk_pixmap_foreign_new (guint32     anid);
+GdkWindow    *gdk_window_foreign_new (guint32       anid);
+
+#endif /* __GDK_X_H__ */
diff --git a/gdk/win32/gdkxid.c b/gdk/win32/gdkxid.c
new file mode 100644 (file)
index 0000000..f6d7bf0
--- /dev/null
@@ -0,0 +1,87 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+
+#include "gdk.h"
+#include "gdkprivate.h"
+#include <stdio.h>
+
+static guint gdk_xid_hash    (XID *xid);
+static gint  gdk_xid_compare (XID *a,
+                             XID *b);
+
+
+static GHashTable *xid_ht = NULL;
+
+
+void
+gdk_xid_table_insert (XID      *xid,
+                     gpointer  data)
+{
+  g_return_if_fail (xid != NULL);
+
+  if (!xid_ht)
+    xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash,
+                              (GCompareFunc) gdk_xid_compare);
+
+  g_hash_table_insert (xid_ht, xid, data);
+}
+
+void
+gdk_xid_table_remove (XID xid)
+{
+  if (!xid_ht)
+    xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash,
+                              (GCompareFunc) gdk_xid_compare);
+
+  g_hash_table_remove (xid_ht, &xid);
+}
+
+gpointer
+gdk_xid_table_lookup (XID xid)
+{
+  gpointer data = NULL;
+
+  if (xid_ht)
+    data = g_hash_table_lookup (xid_ht, &xid);
+  
+  return data;
+}
+
+
+static guint
+gdk_xid_hash (XID *xid)
+{
+  return (guint) *xid;
+}
+
+static gint
+gdk_xid_compare (XID *a,
+                XID *b)
+{
+  return (*a == *b);
+}
diff --git a/gdk/win32/rc/cursor00.cur b/gdk/win32/rc/cursor00.cur
new file mode 100644 (file)
index 0000000..337e6d4
Binary files /dev/null and b/gdk/win32/rc/cursor00.cur differ
diff --git a/gdk/win32/rc/cursor02.cur b/gdk/win32/rc/cursor02.cur
new file mode 100644 (file)
index 0000000..fbc4774
Binary files /dev/null and b/gdk/win32/rc/cursor02.cur differ
diff --git a/gdk/win32/rc/cursor04.cur b/gdk/win32/rc/cursor04.cur
new file mode 100644 (file)
index 0000000..9634c42
Binary files /dev/null and b/gdk/win32/rc/cursor04.cur differ
diff --git a/gdk/win32/rc/cursor06.cur b/gdk/win32/rc/cursor06.cur
new file mode 100644 (file)
index 0000000..f7188b2
Binary files /dev/null and b/gdk/win32/rc/cursor06.cur differ
diff --git a/gdk/win32/rc/cursor08.cur b/gdk/win32/rc/cursor08.cur
new file mode 100644 (file)
index 0000000..d9f15f7
Binary files /dev/null and b/gdk/win32/rc/cursor08.cur differ
diff --git a/gdk/win32/rc/cursor0a.cur b/gdk/win32/rc/cursor0a.cur
new file mode 100644 (file)
index 0000000..3f8ef45
Binary files /dev/null and b/gdk/win32/rc/cursor0a.cur differ
diff --git a/gdk/win32/rc/cursor0c.cur b/gdk/win32/rc/cursor0c.cur
new file mode 100644 (file)
index 0000000..1014edd
Binary files /dev/null and b/gdk/win32/rc/cursor0c.cur differ
diff --git a/gdk/win32/rc/cursor0e.cur b/gdk/win32/rc/cursor0e.cur
new file mode 100644 (file)
index 0000000..964058d
Binary files /dev/null and b/gdk/win32/rc/cursor0e.cur differ
diff --git a/gdk/win32/rc/cursor10.cur b/gdk/win32/rc/cursor10.cur
new file mode 100644 (file)
index 0000000..c4f7809
Binary files /dev/null and b/gdk/win32/rc/cursor10.cur differ
diff --git a/gdk/win32/rc/cursor12.cur b/gdk/win32/rc/cursor12.cur
new file mode 100644 (file)
index 0000000..920c936
Binary files /dev/null and b/gdk/win32/rc/cursor12.cur differ
diff --git a/gdk/win32/rc/cursor14.cur b/gdk/win32/rc/cursor14.cur
new file mode 100644 (file)
index 0000000..c7de122
Binary files /dev/null and b/gdk/win32/rc/cursor14.cur differ
diff --git a/gdk/win32/rc/cursor16.cur b/gdk/win32/rc/cursor16.cur
new file mode 100644 (file)
index 0000000..cfc08f2
Binary files /dev/null and b/gdk/win32/rc/cursor16.cur differ
diff --git a/gdk/win32/rc/cursor18.cur b/gdk/win32/rc/cursor18.cur
new file mode 100644 (file)
index 0000000..95ed2ee
Binary files /dev/null and b/gdk/win32/rc/cursor18.cur differ
diff --git a/gdk/win32/rc/cursor1a.cur b/gdk/win32/rc/cursor1a.cur
new file mode 100644 (file)
index 0000000..ea51361
Binary files /dev/null and b/gdk/win32/rc/cursor1a.cur differ
diff --git a/gdk/win32/rc/cursor1c.cur b/gdk/win32/rc/cursor1c.cur
new file mode 100644 (file)
index 0000000..f46fee6
Binary files /dev/null and b/gdk/win32/rc/cursor1c.cur differ
diff --git a/gdk/win32/rc/cursor1e.cur b/gdk/win32/rc/cursor1e.cur
new file mode 100644 (file)
index 0000000..49fa7f7
Binary files /dev/null and b/gdk/win32/rc/cursor1e.cur differ
diff --git a/gdk/win32/rc/cursor20.cur b/gdk/win32/rc/cursor20.cur
new file mode 100644 (file)
index 0000000..cf177a1
Binary files /dev/null and b/gdk/win32/rc/cursor20.cur differ
diff --git a/gdk/win32/rc/cursor22.cur b/gdk/win32/rc/cursor22.cur
new file mode 100644 (file)
index 0000000..2f8e912
Binary files /dev/null and b/gdk/win32/rc/cursor22.cur differ
diff --git a/gdk/win32/rc/cursor24.cur b/gdk/win32/rc/cursor24.cur
new file mode 100644 (file)
index 0000000..87ba5b4
Binary files /dev/null and b/gdk/win32/rc/cursor24.cur differ
diff --git a/gdk/win32/rc/cursor26.cur b/gdk/win32/rc/cursor26.cur
new file mode 100644 (file)
index 0000000..0b2dbd2
Binary files /dev/null and b/gdk/win32/rc/cursor26.cur differ
diff --git a/gdk/win32/rc/cursor28.cur b/gdk/win32/rc/cursor28.cur
new file mode 100644 (file)
index 0000000..30550f9
Binary files /dev/null and b/gdk/win32/rc/cursor28.cur differ
diff --git a/gdk/win32/rc/cursor2a.cur b/gdk/win32/rc/cursor2a.cur
new file mode 100644 (file)
index 0000000..8dca432
Binary files /dev/null and b/gdk/win32/rc/cursor2a.cur differ
diff --git a/gdk/win32/rc/cursor2c.cur b/gdk/win32/rc/cursor2c.cur
new file mode 100644 (file)
index 0000000..7be3494
Binary files /dev/null and b/gdk/win32/rc/cursor2c.cur differ
diff --git a/gdk/win32/rc/cursor2e.cur b/gdk/win32/rc/cursor2e.cur
new file mode 100644 (file)
index 0000000..7a0bc69
Binary files /dev/null and b/gdk/win32/rc/cursor2e.cur differ
diff --git a/gdk/win32/rc/cursor30.cur b/gdk/win32/rc/cursor30.cur
new file mode 100644 (file)
index 0000000..70ef4fd
Binary files /dev/null and b/gdk/win32/rc/cursor30.cur differ
diff --git a/gdk/win32/rc/cursor32.cur b/gdk/win32/rc/cursor32.cur
new file mode 100644 (file)
index 0000000..93b5c47
Binary files /dev/null and b/gdk/win32/rc/cursor32.cur differ
diff --git a/gdk/win32/rc/cursor34.cur b/gdk/win32/rc/cursor34.cur
new file mode 100644 (file)
index 0000000..0fad3f1
Binary files /dev/null and b/gdk/win32/rc/cursor34.cur differ
diff --git a/gdk/win32/rc/cursor36.cur b/gdk/win32/rc/cursor36.cur
new file mode 100644 (file)
index 0000000..fc8d4f6
Binary files /dev/null and b/gdk/win32/rc/cursor36.cur differ
diff --git a/gdk/win32/rc/cursor38.cur b/gdk/win32/rc/cursor38.cur
new file mode 100644 (file)
index 0000000..4447d7d
Binary files /dev/null and b/gdk/win32/rc/cursor38.cur differ
diff --git a/gdk/win32/rc/cursor3a.cur b/gdk/win32/rc/cursor3a.cur
new file mode 100644 (file)
index 0000000..d359587
Binary files /dev/null and b/gdk/win32/rc/cursor3a.cur differ
diff --git a/gdk/win32/rc/cursor3c.cur b/gdk/win32/rc/cursor3c.cur
new file mode 100644 (file)
index 0000000..6a3111d
Binary files /dev/null and b/gdk/win32/rc/cursor3c.cur differ
diff --git a/gdk/win32/rc/cursor3e.cur b/gdk/win32/rc/cursor3e.cur
new file mode 100644 (file)
index 0000000..fa6fe5b
Binary files /dev/null and b/gdk/win32/rc/cursor3e.cur differ
diff --git a/gdk/win32/rc/cursor40.cur b/gdk/win32/rc/cursor40.cur
new file mode 100644 (file)
index 0000000..f07bf4f
Binary files /dev/null and b/gdk/win32/rc/cursor40.cur differ
diff --git a/gdk/win32/rc/cursor42.cur b/gdk/win32/rc/cursor42.cur
new file mode 100644 (file)
index 0000000..387d5f0
Binary files /dev/null and b/gdk/win32/rc/cursor42.cur differ
diff --git a/gdk/win32/rc/cursor44.cur b/gdk/win32/rc/cursor44.cur
new file mode 100644 (file)
index 0000000..190320c
Binary files /dev/null and b/gdk/win32/rc/cursor44.cur differ
diff --git a/gdk/win32/rc/cursor46.cur b/gdk/win32/rc/cursor46.cur
new file mode 100644 (file)
index 0000000..3e97094
Binary files /dev/null and b/gdk/win32/rc/cursor46.cur differ
diff --git a/gdk/win32/rc/cursor48.cur b/gdk/win32/rc/cursor48.cur
new file mode 100644 (file)
index 0000000..2a56897
Binary files /dev/null and b/gdk/win32/rc/cursor48.cur differ
diff --git a/gdk/win32/rc/cursor4a.cur b/gdk/win32/rc/cursor4a.cur
new file mode 100644 (file)
index 0000000..30febfa
Binary files /dev/null and b/gdk/win32/rc/cursor4a.cur differ
diff --git a/gdk/win32/rc/cursor4c.cur b/gdk/win32/rc/cursor4c.cur
new file mode 100644 (file)
index 0000000..0407d77
Binary files /dev/null and b/gdk/win32/rc/cursor4c.cur differ
diff --git a/gdk/win32/rc/cursor4e.cur b/gdk/win32/rc/cursor4e.cur
new file mode 100644 (file)
index 0000000..a58e3db
Binary files /dev/null and b/gdk/win32/rc/cursor4e.cur differ
diff --git a/gdk/win32/rc/cursor50.cur b/gdk/win32/rc/cursor50.cur
new file mode 100644 (file)
index 0000000..7352420
Binary files /dev/null and b/gdk/win32/rc/cursor50.cur differ
diff --git a/gdk/win32/rc/cursor52.cur b/gdk/win32/rc/cursor52.cur
new file mode 100644 (file)
index 0000000..435f99f
Binary files /dev/null and b/gdk/win32/rc/cursor52.cur differ
diff --git a/gdk/win32/rc/cursor54.cur b/gdk/win32/rc/cursor54.cur
new file mode 100644 (file)
index 0000000..54eb4f2
Binary files /dev/null and b/gdk/win32/rc/cursor54.cur differ
diff --git a/gdk/win32/rc/cursor56.cur b/gdk/win32/rc/cursor56.cur
new file mode 100644 (file)
index 0000000..c808bd4
Binary files /dev/null and b/gdk/win32/rc/cursor56.cur differ
diff --git a/gdk/win32/rc/cursor58.cur b/gdk/win32/rc/cursor58.cur
new file mode 100644 (file)
index 0000000..98b6a2f
Binary files /dev/null and b/gdk/win32/rc/cursor58.cur differ
diff --git a/gdk/win32/rc/cursor5a.cur b/gdk/win32/rc/cursor5a.cur
new file mode 100644 (file)
index 0000000..b00070e
Binary files /dev/null and b/gdk/win32/rc/cursor5a.cur differ
diff --git a/gdk/win32/rc/cursor5c.cur b/gdk/win32/rc/cursor5c.cur
new file mode 100644 (file)
index 0000000..a407b55
Binary files /dev/null and b/gdk/win32/rc/cursor5c.cur differ
diff --git a/gdk/win32/rc/cursor5e.cur b/gdk/win32/rc/cursor5e.cur
new file mode 100644 (file)
index 0000000..ab3449f
Binary files /dev/null and b/gdk/win32/rc/cursor5e.cur differ
diff --git a/gdk/win32/rc/cursor60.cur b/gdk/win32/rc/cursor60.cur
new file mode 100644 (file)
index 0000000..847969d
Binary files /dev/null and b/gdk/win32/rc/cursor60.cur differ
diff --git a/gdk/win32/rc/cursor62.cur b/gdk/win32/rc/cursor62.cur
new file mode 100644 (file)
index 0000000..36404a5
Binary files /dev/null and b/gdk/win32/rc/cursor62.cur differ
diff --git a/gdk/win32/rc/cursor64.cur b/gdk/win32/rc/cursor64.cur
new file mode 100644 (file)
index 0000000..a6bdd0e
Binary files /dev/null and b/gdk/win32/rc/cursor64.cur differ
diff --git a/gdk/win32/rc/cursor66.cur b/gdk/win32/rc/cursor66.cur
new file mode 100644 (file)
index 0000000..81d53b4
Binary files /dev/null and b/gdk/win32/rc/cursor66.cur differ
diff --git a/gdk/win32/rc/cursor68.cur b/gdk/win32/rc/cursor68.cur
new file mode 100644 (file)
index 0000000..27cfaf0
Binary files /dev/null and b/gdk/win32/rc/cursor68.cur differ
diff --git a/gdk/win32/rc/cursor6a.cur b/gdk/win32/rc/cursor6a.cur
new file mode 100644 (file)
index 0000000..20f138e
Binary files /dev/null and b/gdk/win32/rc/cursor6a.cur differ
diff --git a/gdk/win32/rc/cursor6c.cur b/gdk/win32/rc/cursor6c.cur
new file mode 100644 (file)
index 0000000..1e8d6d8
Binary files /dev/null and b/gdk/win32/rc/cursor6c.cur differ
diff --git a/gdk/win32/rc/cursor6e.cur b/gdk/win32/rc/cursor6e.cur
new file mode 100644 (file)
index 0000000..3a9b6b0
Binary files /dev/null and b/gdk/win32/rc/cursor6e.cur differ
diff --git a/gdk/win32/rc/cursor70.cur b/gdk/win32/rc/cursor70.cur
new file mode 100644 (file)
index 0000000..e2d7673
Binary files /dev/null and b/gdk/win32/rc/cursor70.cur differ
diff --git a/gdk/win32/rc/cursor72.cur b/gdk/win32/rc/cursor72.cur
new file mode 100644 (file)
index 0000000..4994c6e
Binary files /dev/null and b/gdk/win32/rc/cursor72.cur differ
diff --git a/gdk/win32/rc/cursor74.cur b/gdk/win32/rc/cursor74.cur
new file mode 100644 (file)
index 0000000..d5e4361
Binary files /dev/null and b/gdk/win32/rc/cursor74.cur differ
diff --git a/gdk/win32/rc/cursor76.cur b/gdk/win32/rc/cursor76.cur
new file mode 100644 (file)
index 0000000..34f402a
Binary files /dev/null and b/gdk/win32/rc/cursor76.cur differ
diff --git a/gdk/win32/rc/cursor78.cur b/gdk/win32/rc/cursor78.cur
new file mode 100644 (file)
index 0000000..70e25dd
Binary files /dev/null and b/gdk/win32/rc/cursor78.cur differ
diff --git a/gdk/win32/rc/cursor7a.cur b/gdk/win32/rc/cursor7a.cur
new file mode 100644 (file)
index 0000000..5ea95c4
Binary files /dev/null and b/gdk/win32/rc/cursor7a.cur differ
diff --git a/gdk/win32/rc/cursor7c.cur b/gdk/win32/rc/cursor7c.cur
new file mode 100644 (file)
index 0000000..2b46717
Binary files /dev/null and b/gdk/win32/rc/cursor7c.cur differ
diff --git a/gdk/win32/rc/cursor7e.cur b/gdk/win32/rc/cursor7e.cur
new file mode 100644 (file)
index 0000000..4b24e50
Binary files /dev/null and b/gdk/win32/rc/cursor7e.cur differ
diff --git a/gdk/win32/rc/cursor80.cur b/gdk/win32/rc/cursor80.cur
new file mode 100644 (file)
index 0000000..a3955a5
Binary files /dev/null and b/gdk/win32/rc/cursor80.cur differ
diff --git a/gdk/win32/rc/cursor82.cur b/gdk/win32/rc/cursor82.cur
new file mode 100644 (file)
index 0000000..984cfba
Binary files /dev/null and b/gdk/win32/rc/cursor82.cur differ
diff --git a/gdk/win32/rc/cursor84.cur b/gdk/win32/rc/cursor84.cur
new file mode 100644 (file)
index 0000000..cd6807e
Binary files /dev/null and b/gdk/win32/rc/cursor84.cur differ
diff --git a/gdk/win32/rc/cursor86.cur b/gdk/win32/rc/cursor86.cur
new file mode 100644 (file)
index 0000000..2d38c03
Binary files /dev/null and b/gdk/win32/rc/cursor86.cur differ
diff --git a/gdk/win32/rc/cursor88.cur b/gdk/win32/rc/cursor88.cur
new file mode 100644 (file)
index 0000000..62b8061
Binary files /dev/null and b/gdk/win32/rc/cursor88.cur differ
diff --git a/gdk/win32/rc/cursor8a.cur b/gdk/win32/rc/cursor8a.cur
new file mode 100644 (file)
index 0000000..6c5358d
Binary files /dev/null and b/gdk/win32/rc/cursor8a.cur differ
diff --git a/gdk/win32/rc/cursor8c.cur b/gdk/win32/rc/cursor8c.cur
new file mode 100644 (file)
index 0000000..103010b
Binary files /dev/null and b/gdk/win32/rc/cursor8c.cur differ
diff --git a/gdk/win32/rc/cursor8e.cur b/gdk/win32/rc/cursor8e.cur
new file mode 100644 (file)
index 0000000..a500a38
Binary files /dev/null and b/gdk/win32/rc/cursor8e.cur differ
diff --git a/gdk/win32/rc/cursor90.cur b/gdk/win32/rc/cursor90.cur
new file mode 100644 (file)
index 0000000..08731f8
Binary files /dev/null and b/gdk/win32/rc/cursor90.cur differ
diff --git a/gdk/win32/rc/cursor92.cur b/gdk/win32/rc/cursor92.cur
new file mode 100644 (file)
index 0000000..4364b5d
Binary files /dev/null and b/gdk/win32/rc/cursor92.cur differ
diff --git a/gdk/win32/rc/cursor94.cur b/gdk/win32/rc/cursor94.cur
new file mode 100644 (file)
index 0000000..7777d53
Binary files /dev/null and b/gdk/win32/rc/cursor94.cur differ
diff --git a/gdk/win32/rc/cursor96.cur b/gdk/win32/rc/cursor96.cur
new file mode 100644 (file)
index 0000000..cecaea3
Binary files /dev/null and b/gdk/win32/rc/cursor96.cur differ
diff --git a/gdk/win32/rc/cursor98.cur b/gdk/win32/rc/cursor98.cur
new file mode 100644 (file)
index 0000000..5cab68e
Binary files /dev/null and b/gdk/win32/rc/cursor98.cur differ
diff --git a/gdk/win32/rc/gdk.rc b/gdk/win32/rc/gdk.rc
new file mode 100644 (file)
index 0000000..b52b3f1
--- /dev/null
@@ -0,0 +1,78 @@
+GTK_ICON               ICON                    "gtk.ico"
+X_cursor                CURSOR  DISCARDABLE     "cursor00.cur"
+arrow                   CURSOR  DISCARDABLE     "cursor02.cur"
+based_arrow_down        CURSOR  DISCARDABLE     "cursor04.cur"
+based_arrow_up          CURSOR  DISCARDABLE     "cursor06.cur"
+boat                    CURSOR  DISCARDABLE     "cursor08.cur"
+bogosity                CURSOR  DISCARDABLE     "cursor0a.cur"
+bottom_left_corner      CURSOR  DISCARDABLE     "cursor0c.cur"
+bottom_right_corner     CURSOR  DISCARDABLE     "cursor0e.cur"
+bottom_side             CURSOR  DISCARDABLE     "cursor10.cur"
+bottom_tee              CURSOR  DISCARDABLE     "cursor12.cur"
+box_spiral              CURSOR  DISCARDABLE     "cursor14.cur"
+center_ptr              CURSOR  DISCARDABLE     "cursor16.cur"
+circle                  CURSOR  DISCARDABLE     "cursor18.cur"
+clock                   CURSOR  DISCARDABLE     "cursor1a.cur"
+coffee_mug              CURSOR  DISCARDABLE     "cursor1c.cur"
+cross                   CURSOR  DISCARDABLE     "cursor1e.cur"
+cross_reverse           CURSOR  DISCARDABLE     "cursor20.cur"
+crosshair               CURSOR  DISCARDABLE     "cursor22.cur"
+diamond_cross           CURSOR  DISCARDABLE     "cursor24.cur"
+dot                     CURSOR  DISCARDABLE     "cursor26.cur"
+dotbox                  CURSOR  DISCARDABLE     "cursor28.cur"
+double_arrow            CURSOR  DISCARDABLE     "cursor2a.cur"
+draft_large             CURSOR  DISCARDABLE     "cursor2c.cur"
+draft_small             CURSOR  DISCARDABLE     "cursor2e.cur"
+draped_box              CURSOR  DISCARDABLE     "cursor30.cur"
+exchange                CURSOR  DISCARDABLE     "cursor32.cur"
+fleur                   CURSOR  DISCARDABLE     "cursor34.cur"
+gobbler                 CURSOR  DISCARDABLE     "cursor36.cur"
+gumby                   CURSOR  DISCARDABLE     "cursor38.cur"
+hand1                   CURSOR  DISCARDABLE     "cursor3a.cur"
+hand2                   CURSOR  DISCARDABLE     "cursor3c.cur"
+heart                   CURSOR  DISCARDABLE     "cursor3e.cur"
+icon                    CURSOR  DISCARDABLE     "cursor40.cur"
+iron_cross              CURSOR  DISCARDABLE     "cursor42.cur"
+left_ptr                CURSOR  DISCARDABLE     "cursor44.cur"
+left_side               CURSOR  DISCARDABLE     "cursor46.cur"
+left_tee                CURSOR  DISCARDABLE     "cursor48.cur"
+leftbutton              CURSOR  DISCARDABLE     "cursor4a.cur"
+ll_angle                CURSOR  DISCARDABLE     "cursor4c.cur"
+lr_angle                CURSOR  DISCARDABLE     "cursor4e.cur"
+man                     CURSOR  DISCARDABLE     "cursor50.cur"
+middlebutton            CURSOR  DISCARDABLE     "cursor52.cur"
+mouse                   CURSOR  DISCARDABLE     "cursor54.cur"
+pencil                  CURSOR  DISCARDABLE     "cursor56.cur"
+pirate                  CURSOR  DISCARDABLE     "cursor58.cur"
+plus                    CURSOR  DISCARDABLE     "cursor5a.cur"
+question_arrow          CURSOR  DISCARDABLE     "cursor5c.cur"
+right_ptr               CURSOR  DISCARDABLE     "cursor5e.cur"
+right_side              CURSOR  DISCARDABLE     "cursor60.cur"
+right_tee               CURSOR  DISCARDABLE     "cursor62.cur"
+rightbutton             CURSOR  DISCARDABLE     "cursor64.cur"
+rtl_logo                CURSOR  DISCARDABLE     "cursor66.cur"
+sailboat                CURSOR  DISCARDABLE     "cursor68.cur"
+sb_down_arrow           CURSOR  DISCARDABLE     "cursor6a.cur"
+sb_h_double_arrow       CURSOR  DISCARDABLE     "cursor6c.cur"
+sb_left_arrow           CURSOR  DISCARDABLE     "cursor6e.cur"
+sb_right_arrow          CURSOR  DISCARDABLE     "cursor70.cur"
+sb_up_arrow             CURSOR  DISCARDABLE     "cursor72.cur"
+sb_v_double_arrow       CURSOR  DISCARDABLE     "cursor74.cur"
+shuttle                 CURSOR  DISCARDABLE     "cursor76.cur"
+sizing                  CURSOR  DISCARDABLE     "cursor78.cur"
+spider                  CURSOR  DISCARDABLE     "cursor7a.cur"
+spraycan                CURSOR  DISCARDABLE     "cursor7c.cur"
+star                    CURSOR  DISCARDABLE     "cursor7e.cur"
+target                  CURSOR  DISCARDABLE     "cursor80.cur"
+tcross                  CURSOR  DISCARDABLE     "cursor82.cur"
+top_left_arrow          CURSOR  DISCARDABLE     "cursor84.cur"
+top_left_corner         CURSOR  DISCARDABLE     "cursor86.cur"
+top_right_corner        CURSOR  DISCARDABLE     "cursor88.cur"
+top_side                CURSOR  DISCARDABLE     "cursor8a.cur"
+top_tee                 CURSOR  DISCARDABLE     "cursor8c.cur"
+trek                    CURSOR  DISCARDABLE     "cursor8e.cur"
+ul_angle                CURSOR  DISCARDABLE     "cursor90.cur"
+umbrella                CURSOR  DISCARDABLE     "cursor92.cur"
+ur_angle                CURSOR  DISCARDABLE     "cursor94.cur"
+xterm                   CURSOR  DISCARDABLE     "cursor98.cur"
+watch                   CURSOR  DISCARDABLE     "cursor96.cur"
diff --git a/gdk/win32/rc/gtk.ico b/gdk/win32/rc/gtk.ico
new file mode 100644 (file)
index 0000000..54ee412
Binary files /dev/null and b/gdk/win32/rc/gtk.ico differ